2 void generic_plat_blocked()
4 if(self.dmg && other.takedamage != DAMAGE_NO) {
5 if(self.dmgtime2 < time) {
6 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
7 self.dmgtime2 = time + self.dmgtime;
10 // Gib dead/dying stuff
11 if(other.deadflag != DEAD_NO)
12 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
18 float STATE_BOTTOM = 1;
22 .entity trigger_field;
24 void() plat_center_touch;
25 void() plat_outside_touch;
26 void() plat_trigger_use;
30 float PLAT_LOW_TRIGGER = 1;
32 void plat_spawn_inside_trigger()
38 trigger.touch = plat_center_touch;
39 trigger.movetype = MOVETYPE_NONE;
40 trigger.solid = SOLID_TRIGGER;
43 tmin = self.absmin + '25 25 0';
44 tmax = self.absmax - '25 25 -8';
45 tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
46 if (self.spawnflags & PLAT_LOW_TRIGGER)
49 if (self.size_x <= 50)
51 tmin_x = (self.mins_x + self.maxs_x) / 2;
54 if (self.size_y <= 50)
56 tmin_y = (self.mins_y + self.maxs_y) / 2;
60 setsize (trigger, tmin, tmax);
65 sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
67 self.think = plat_go_down;
68 self.nextthink = self.ltime + 3;
71 void plat_hit_bottom()
73 sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
79 sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_NORM);
81 SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
86 sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_NORM);
88 SUB_CalcMove (self.pos1, self.speed, plat_hit_top);
91 void plat_center_touch()
93 if not(other.iscreature)
96 if (other.health <= 0)
102 else if (self.state == 1)
103 self.nextthink = self.ltime + 1; // delay going down
106 void plat_outside_touch()
108 if not(other.iscreature)
111 if (other.health <= 0)
119 void plat_trigger_use()
122 return; // already activated
129 if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
130 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
132 if((self.dmg) && (other.takedamage != DAMAGE_NO)) { // Shall we bite?
133 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
134 // Gib dead/dying stuff
135 if(other.deadflag != DEAD_NO)
136 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
141 else if (self.state == 3)
143 // when in other states, then the plat_crush event came delayed after
144 // plat state already had changed
145 // this isn't a bug per se!
153 objerror ("plat_use: not in up state");
157 .string sound1, sound2;
163 setorigin (self, self.pos1);
169 setorigin (self, self.pos2);
171 self.use = plat_trigger_use;
175 void spawnfunc_path_corner() { }
176 void spawnfunc_func_plat()
183 if (self.sounds == 0)
186 if(self.spawnflags & 4)
189 if(self.dmg && (!self.message))
190 self.message = "was squished";
191 if(self.dmg && (!self.message2))
192 self.message2 = "was squished by";
194 if (self.sounds == 1)
196 precache_sound ("plats/plat1.wav");
197 precache_sound ("plats/plat2.wav");
198 self.noise = "plats/plat1.wav";
199 self.noise1 = "plats/plat2.wav";
202 if (self.sounds == 2)
204 precache_sound ("plats/medplat1.wav");
205 precache_sound ("plats/medplat2.wav");
206 self.noise = "plats/medplat1.wav";
207 self.noise1 = "plats/medplat2.wav";
212 precache_sound (self.sound1);
213 self.noise = self.sound1;
217 precache_sound (self.sound2);
218 self.noise1 = self.sound2;
221 self.mangle = self.angles;
222 self.angles = '0 0 0';
224 self.classname = "plat";
225 if not(InitMovingBrushTrigger())
227 self.effects |= EF_LOWPRECISION;
228 setsize (self, self.mins , self.maxs);
230 self.blocked = plat_crush;
235 self.pos1 = self.origin;
236 self.pos2 = self.origin;
237 self.pos2_z = self.origin_z - self.size_z + 8;
239 plat_spawn_inside_trigger (); // the "start moving" trigger
241 self.reset = plat_reset;
250 stopsoundto(MSG_BROADCAST, self, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
258 self.think = train_next;
259 self.nextthink = self.ltime + self.wait;
273 targ = find(world, targetname, self.target);
275 self.target = targ.target;
277 objerror("train_next: no next target");
278 self.wait = targ.wait;
283 SUB_CalcMove(targ.origin - self.mins, targ.speed, train_wait);
285 SUB_CalcMove(targ.origin - self.mins, self.speed, train_wait);
288 sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
291 void func_train_find()
294 targ = find(world, targetname, self.target);
295 self.target = targ.target;
297 objerror("func_train_find: no next target");
298 setorigin(self, targ.origin - self.mins);
299 self.nextthink = self.ltime + 1;
300 self.think = train_next;
303 /*QUAKED spawnfunc_func_train (0 .5 .8) ?
304 Ridable platform, targets spawnfunc_path_corner path to follow.
305 speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
306 target : targetname of first spawnfunc_path_corner (starts here)
308 void spawnfunc_func_train()
310 if (self.noise != "")
311 precache_sound(self.noise);
314 objerror("func_train without a target");
318 if not(InitMovingBrushTrigger())
320 self.effects |= EF_LOWPRECISION;
322 // wait for targets to spawn
323 InitializeEntity(self, func_train_find, INITPRIO_SETLOCATION);
325 self.blocked = generic_plat_blocked;
326 if(self.dmg & (!self.message))
327 self.message = " was squished";
328 if(self.dmg && (!self.message2))
329 self.message2 = "was squished by";
330 if(self.dmg && (!self.dmgtime))
332 self.dmgtime2 = time;
334 // TODO make a reset function for this one
337 void func_rotating_setactive(float astate)
340 if (astate == ACTIVE_TOGGLE)
342 if(self.active == ACTIVE_ACTIVE)
343 self.active = ACTIVE_NOT;
345 self.active = ACTIVE_ACTIVE;
348 self.active = astate;
350 if(self.active == ACTIVE_NOT)
351 self.avelocity = '0 0 0';
353 self.avelocity = self.pos1;
356 /*QUAKED spawnfunc_func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
357 Brush model that spins in place on one axis (default Z).
358 speed : speed to rotate (in degrees per second)
359 noise : path/name of looping .wav file to play.
360 dmg : Do this mutch dmg every .dmgtime intervall when blocked
364 void spawnfunc_func_rotating()
366 if (self.noise != "")
368 precache_sound(self.noise);
369 ambientsound(self.origin, self.noise, VOL_BASE, ATTN_IDLE);
372 self.active = ACTIVE_ACTIVE;
373 self.setactive = func_rotating_setactive;
377 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
378 if (self.spawnflags & 4) // X (untested)
379 self.avelocity = '0 0 1' * self.speed;
380 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
381 else if (self.spawnflags & 8) // Y (untested)
382 self.avelocity = '1 0 0' * self.speed;
383 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
385 self.avelocity = '0 1 0' * self.speed;
387 self.pos1 = self.avelocity;
389 if(self.dmg & (!self.message))
390 self.message = " was squished";
391 if(self.dmg && (!self.message2))
392 self.message2 = "was squished by";
395 if(self.dmg && (!self.dmgtime))
398 self.dmgtime2 = time;
400 if not(InitMovingBrushTrigger())
402 // no EF_LOWPRECISION here, as rounding angles is bad
404 self.blocked = generic_plat_blocked;
406 // wait for targets to spawn
407 self.nextthink = self.ltime + 999999999;
408 self.think = SUB_Null;
410 // TODO make a reset function for this one
414 void func_bobbing_controller_think()
417 self.nextthink = time + 0.1;
419 if not (self.owner.active == ACTIVE_ACTIVE)
421 self.owner.velocity = '0 0 0';
425 // calculate sinewave using makevectors
426 makevectors((self.nextthink * self.owner.cnt + self.owner.phase * 360) * '0 1 0');
427 v = self.owner.destvec + self.owner.movedir * v_forward_y;
428 if(self.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed
429 // * 10 so it will arrive in 0.1 sec
430 self.owner.velocity = (v - self.owner.origin) * 10;
433 /*QUAKED spawnfunc_func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
434 Brush model that moves back and forth on one axis (default Z).
435 speed : how long one cycle takes in seconds (default 4)
436 height : how far the cycle moves (default 32)
437 phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
438 noise : path/name of looping .wav file to play.
439 dmg : Do this mutch dmg every .dmgtime intervall when blocked
442 void spawnfunc_func_bobbing()
445 if (self.noise != "")
447 precache_sound(self.noise);
448 soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
454 // center of bobbing motion
455 self.destvec = self.origin;
456 // time scale to get degrees
457 self.cnt = 360 / self.speed;
459 self.active = ACTIVE_ACTIVE;
461 // damage when blocked
462 self.blocked = generic_plat_blocked;
463 if(self.dmg & (!self.message))
464 self.message = " was squished";
465 if(self.dmg && (!self.message2))
466 self.message2 = "was squished by";
467 if(self.dmg && (!self.dmgtime))
469 self.dmgtime2 = time;
472 if (self.spawnflags & 1) // X
473 self.movedir = '1 0 0' * self.height;
474 else if (self.spawnflags & 2) // Y
475 self.movedir = '0 1 0' * self.height;
477 self.movedir = '0 0 1' * self.height;
479 if not(InitMovingBrushTrigger())
482 // wait for targets to spawn
483 controller = spawn();
484 controller.classname = "func_bobbing_controller";
485 controller.owner = self;
486 controller.nextthink = time + 1;
487 controller.think = func_bobbing_controller_think;
488 self.nextthink = self.ltime + 999999999;
489 self.think = SUB_Null;
491 // Savage: Reduce bandwith, critical on e.g. nexdm02
492 self.effects |= EF_LOWPRECISION;
494 // TODO make a reset function for this one
498 void func_pendulum_controller_think()
501 self.nextthink = time + 0.1;
503 if not (self.owner.active == ACTIVE_ACTIVE)
505 self.owner.avelocity_x = 0;
509 // calculate sinewave using makevectors
510 makevectors((self.nextthink * self.owner.freq + self.owner.phase) * '0 360 0');
511 v = self.owner.speed * v_forward_y + self.cnt;
512 if(self.owner.classname == "func_pendulum") // don't brake stuff if the func_bobbing was killtarget'ed
514 // * 10 so it will arrive in 0.1 sec
515 self.owner.avelocity_z = (remainder(v - self.owner.angles_z, 360)) * 10;
519 void spawnfunc_func_pendulum()
522 if (self.noise != "")
524 precache_sound(self.noise);
525 soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
528 self.active = ACTIVE_ACTIVE;
530 // keys: angle, speed, phase, noise, freq
534 // not initializing self.dmg to 2, to allow damageless pendulum
536 if(self.dmg & (!self.message))
537 self.message = " was squished";
538 if(self.dmg && (!self.message2))
539 self.message2 = "was squished by";
540 if(self.dmg && (!self.dmgtime))
542 self.dmgtime2 = time;
544 self.blocked = generic_plat_blocked;
546 self.avelocity_z = 0.0000001;
547 if not(InitMovingBrushTrigger())
552 // find pendulum length (same formula as Q3A)
553 self.freq = 1 / (M_PI * 2) * sqrt(autocvar_sv_gravity / (3 * max(8, fabs(self.mins_z))));
556 // copy initial angle
557 self.cnt = self.angles_z;
559 // wait for targets to spawn
560 controller = spawn();
561 controller.classname = "func_pendulum_controller";
562 controller.owner = self;
563 controller.nextthink = time + 1;
564 controller.think = func_pendulum_controller_think;
565 self.nextthink = self.ltime + 999999999;
566 self.think = SUB_Null;
568 //self.effects |= EF_LOWPRECISION;
570 // TODO make a reset function for this one
573 // button and multiple button
576 void() button_return;
580 self.state = STATE_TOP;
581 self.nextthink = self.ltime + self.wait;
582 self.think = button_return;
583 activator = self.enemy;
585 self.frame = 1; // use alternate textures
590 self.state = STATE_BOTTOM;
595 self.state = STATE_DOWN;
596 SUB_CalcMove (self.pos1, self.speed, button_done);
597 self.frame = 0; // use normal textures
599 self.takedamage = DAMAGE_YES; // can be shot again
603 void button_blocked()
605 // do nothing, just don't come all the way back out
611 self.health = self.max_health;
612 self.takedamage = DAMAGE_NO; // will be reset upon return
614 if (self.state == STATE_UP || self.state == STATE_TOP)
617 if (self.noise != "")
618 sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
620 self.state = STATE_UP;
621 SUB_CalcMove (self.pos2, self.speed, button_wait);
626 self.health = self.max_health;
627 setorigin(self, self.pos1);
628 self.frame = 0; // use normal textures
629 self.state = STATE_BOTTOM;
631 self.takedamage = DAMAGE_YES; // can be shot again
636 // if (activator.classname != "player")
638 // dprint(activator.classname);
639 // dprint(" triggered a button\n");
642 if not (self.active == ACTIVE_ACTIVE)
645 self.enemy = activator;
651 // if (activator.classname != "player")
653 // dprint(activator.classname);
654 // dprint(" touched a button\n");
658 if not(other.iscreature)
660 if(other.velocity * self.movedir < 0)
664 self.enemy = other.owner;
668 void button_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
670 if(self.spawnflags & DOOR_NOSPLASH)
671 if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
673 self.health = self.health - damage;
674 if (self.health <= 0)
676 // if (activator.classname != "player")
678 // dprint(activator.classname);
679 // dprint(" killed a button\n");
681 self.enemy = damage_attacker;
687 /*QUAKED spawnfunc_func_button (0 .5 .8) ?
688 When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
690 "angle" determines the opening direction
691 "target" all entities with a matching targetname will be used
692 "speed" override the default 40 speed
693 "wait" override the default 1 second wait (-1 = never return)
694 "lip" override the default 4 pixel lip remaining at end of move
695 "health" if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the MinstaGib laser
702 void spawnfunc_func_button()
706 if not(InitMovingBrushTrigger())
708 self.effects |= EF_LOWPRECISION;
710 self.blocked = button_blocked;
711 self.use = button_use;
713 // if (self.health == 0) // all buttons are now shootable
717 self.max_health = self.health;
718 self.event_damage = button_damage;
719 self.takedamage = DAMAGE_YES;
722 self.touch = button_touch;
732 precache_sound(self.noise);
734 self.active = ACTIVE_ACTIVE;
736 self.pos1 = self.origin;
737 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
738 self.flags |= FL_NOTARGET;
744 float DOOR_START_OPEN = 1;
745 float DOOR_DONT_LINK = 4;
746 float DOOR_TOGGLE = 32;
750 Doors are similar to buttons, but can spawn a fat trigger field around them
751 to open without a touch, and they link together to form simultanious
754 Door.owner is the master door. If there is only one door, it points to itself.
755 If multiple doors, all will point to a single one.
757 Door.enemy chains from the master door through all doors linked in the chain.
762 =============================================================================
766 =============================================================================
771 void() door_rotating_go_down;
772 void() door_rotating_go_up;
777 if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
778 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
781 if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
782 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
784 //Dont chamge direction for dead or dying stuff
785 if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
788 if (self.state == STATE_DOWN)
789 if (self.classname == "door")
794 door_rotating_go_up ();
797 if (self.classname == "door")
802 door_rotating_go_down ();
806 //gib dying stuff just to make sure
807 if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
808 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
812 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
813 // if a door has a negative wait, it would never come back if blocked,
814 // so let it just squash the object to death real fast
815 /* if (self.wait >= 0)
817 if (self.state == STATE_DOWN)
828 if (self.noise1 != "")
829 sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
830 self.state = STATE_TOP;
831 if (self.spawnflags & DOOR_TOGGLE)
832 return; // don't come down automatically
833 if (self.classname == "door")
835 self.think = door_go_down;
838 self.think = door_rotating_go_down;
840 self.nextthink = self.ltime + self.wait;
843 void door_hit_bottom()
845 if (self.noise1 != "")
846 sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
847 self.state = STATE_BOTTOM;
852 if (self.noise2 != "")
853 sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
856 self.takedamage = DAMAGE_YES;
857 self.health = self.max_health;
860 self.state = STATE_DOWN;
861 SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
866 if (self.state == STATE_UP)
867 return; // already going up
869 if (self.state == STATE_TOP)
870 { // reset top wait time
871 self.nextthink = self.ltime + self.wait;
875 if (self.noise2 != "")
876 sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
877 self.state = STATE_UP;
878 SUB_CalcMove (self.pos2, self.speed, door_hit_top);
881 oldmessage = self.message;
884 self.message = oldmessage;
890 =============================================================================
894 =============================================================================
897 float door_check_keys(void) {
907 if not(door.itemkeys)
910 // this door require a key
911 // only a player can have a key
912 if (other.classname != "player")
915 if (item_keys_usekey(door, other)) {
916 // some keys were used
917 if (other.key_door_messagetime <= time) {
918 play2(other, "misc/talk.wav");
919 centerprint(other, strcat("You also need ", item_keys_keylist(door.itemkeys), "!"));
920 other.key_door_messagetime = time + 2;
924 if (other.key_door_messagetime <= time) {
925 play2(other, "misc/talk.wav");
926 centerprint(other, strcat("You need ", item_keys_keylist(door.itemkeys), "!"));
927 other.key_door_messagetime = time + 2;
932 // door is now unlocked
933 play2(other, "misc/talk.wav");
934 centerprint(other, "Door unlocked!");
946 if (self.owner != self)
947 objerror ("door_fire: self.owner != self");
951 if (self.spawnflags & DOOR_TOGGLE)
953 if (self.state == STATE_UP || self.state == STATE_TOP)
958 if (self.classname == "door")
964 door_rotating_go_down ();
967 } while ( (self != starte) && (self != world) );
973 // trigger all paired doors
977 if (self.classname == "door")
982 // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
983 if ((self.spawnflags & 2) && other.trigger_reverse!=0 && self.lip!=666 && self.state == STATE_BOTTOM)
985 self.lip = 666; // self.lip is used to remember reverse opening direction for door_rotating
986 self.pos2 = '0 0 0' - self.pos2;
988 // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
989 if (!((self.spawnflags & 2) && (self.spawnflags & 8) && self.state == STATE_DOWN
990 && (((self.lip==666) && (other.trigger_reverse==0)) || ((self.lip!=666) && (other.trigger_reverse!=0)))))
992 door_rotating_go_up ();
996 } while ( (self != starte) && (self != world) );
1005 //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
1017 void door_trigger_touch()
1019 if (other.health < 1)
1020 if not(other.iscreature && other.deadflag == DEAD_NO)
1023 if (time < self.attack_finished_single)
1026 // check if door is locked
1027 if (!door_check_keys())
1030 self.attack_finished_single = time + 1;
1039 void door_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
1042 if(self.spawnflags & DOOR_NOSPLASH)
1043 if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
1045 self.health = self.health - damage;
1047 if (self.itemkeys) {
1048 // don't allow opening doors through damage if keys are required
1052 if (self.health <= 0)
1056 self.health = self.max_health;
1057 self.takedamage = DAMAGE_NO; // wil be reset upon return
1073 if(other.classname != "player")
1075 if (self.owner.attack_finished_single > time)
1078 self.owner.attack_finished_single = time + 2;
1080 if (!(self.owner.dmg) && (self.owner.message != ""))
1082 if (other.flags & FL_CLIENT)
1083 centerprint (other, self.owner.message);
1084 play2(other, "misc/talk.wav");
1089 void door_generic_plat_blocked()
1092 if((self.spawnflags & 8) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
1093 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
1096 if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
1097 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
1099 //Dont chamge direction for dead or dying stuff
1100 if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
1103 if (self.state == STATE_DOWN)
1104 door_rotating_go_up ();
1106 door_rotating_go_down ();
1109 //gib dying stuff just to make sure
1110 if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
1111 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
1115 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
1116 // if a door has a negative wait, it would never come back if blocked,
1117 // so let it just squash the object to death real fast
1118 /* if (self.wait >= 0)
1120 if (self.state == STATE_DOWN)
1121 door_rotating_go_up ();
1123 door_rotating_go_down ();
1129 void door_rotating_hit_top()
1131 if (self.noise1 != "")
1132 sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
1133 self.state = STATE_TOP;
1134 if (self.spawnflags & DOOR_TOGGLE)
1135 return; // don't come down automatically
1136 self.think = door_rotating_go_down;
1137 self.nextthink = self.ltime + self.wait;
1140 void door_rotating_hit_bottom()
1142 if (self.noise1 != "")
1143 sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
1144 if (self.lip==666) // self.lip is used to remember reverse opening direction for door_rotating
1146 self.pos2 = '0 0 0' - self.pos2;
1149 self.state = STATE_BOTTOM;
1152 void door_rotating_go_down()
1154 if (self.noise2 != "")
1155 sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
1156 if (self.max_health)
1158 self.takedamage = DAMAGE_YES;
1159 self.health = self.max_health;
1162 self.state = STATE_DOWN;
1163 SUB_CalcAngleMove (self.pos1, self.speed, door_rotating_hit_bottom);
1166 void door_rotating_go_up()
1168 if (self.state == STATE_UP)
1169 return; // already going up
1171 if (self.state == STATE_TOP)
1172 { // reset top wait time
1173 self.nextthink = self.ltime + self.wait;
1176 if (self.noise2 != "")
1177 sound (self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
1178 self.state = STATE_UP;
1179 SUB_CalcAngleMove (self.pos2, self.speed, door_rotating_hit_top);
1182 oldmessage = self.message;
1185 self.message = oldmessage;
1192 =============================================================================
1196 =============================================================================
1200 entity spawn_field(vector fmins, vector fmaxs)
1206 trigger.classname = "doortriggerfield";
1207 trigger.movetype = MOVETYPE_NONE;
1208 trigger.solid = SOLID_TRIGGER;
1209 trigger.owner = self;
1210 trigger.touch = door_trigger_touch;
1214 setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
1219 float EntitiesTouching(entity e1, entity e2)
1221 if (e1.absmin_x > e2.absmax_x)
1223 if (e1.absmin_y > e2.absmax_y)
1225 if (e1.absmin_z > e2.absmax_z)
1227 if (e1.absmax_x < e2.absmin_x)
1229 if (e1.absmax_y < e2.absmin_y)
1231 if (e1.absmax_z < e2.absmin_z)
1247 vector cmins, cmaxs;
1250 return; // already linked by another door
1251 if (self.spawnflags & 4)
1253 self.owner = self.enemy = self;
1261 self.trigger_field = spawn_field(self.absmin, self.absmax);
1263 return; // don't want to link this door
1266 cmins = self.absmin;
1267 cmaxs = self.absmax;
1274 self.owner = starte; // master door
1277 starte.health = self.health;
1279 starte.targetname = self.targetname;
1280 if (self.message != "")
1281 starte.message = self.message;
1283 t = find(t, classname, self.classname);
1286 self.enemy = starte; // make the chain a loop
1288 // shootable, or triggered doors just needed the owner/enemy links,
1289 // they don't spawn a field
1300 self.owner.trigger_field = spawn_field(cmins, cmaxs);
1305 if (EntitiesTouching(self,t))
1308 objerror ("cross connected doors");
1313 if (t.absmin_x < cmins_x)
1314 cmins_x = t.absmin_x;
1315 if (t.absmin_y < cmins_y)
1316 cmins_y = t.absmin_y;
1317 if (t.absmin_z < cmins_z)
1318 cmins_z = t.absmin_z;
1319 if (t.absmax_x > cmaxs_x)
1320 cmaxs_x = t.absmax_x;
1321 if (t.absmax_y > cmaxs_y)
1322 cmaxs_y = t.absmax_y;
1323 if (t.absmax_z > cmaxs_z)
1324 cmaxs_z = t.absmax_z;
1331 /*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
1332 if two doors touch, they are assumed to be connected and operate as a unit.
1334 TOGGLE causes the door to wait in both the start and end states for a trigger event.
1336 START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
1338 GOLD_KEY causes the door to open only if the activator holds a gold key.
1340 SILVER_KEY causes the door to open only if the activator holds a silver key.
1342 "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
1343 "angle" determines the opening direction
1344 "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
1345 "health" if set, door must be shot open
1346 "speed" movement speed (100 default)
1347 "wait" wait before returning (3 default, -1 = never return)
1348 "lip" lip remaining at end of move (8 default)
1349 "dmg" damage to inflict when blocked (2 default)
1356 FIXME: only one sound set available at the time being
1360 void door_init_startopen()
1362 setorigin (self, self.pos2);
1363 self.pos2 = self.pos1;
1364 self.pos1 = self.origin;
1369 setorigin(self, self.pos1);
1370 self.velocity = '0 0 0';
1371 self.state = STATE_BOTTOM;
1372 self.think = SUB_Null;
1375 // spawnflags require key (for now only func_door)
1376 #define SPAWNFLAGS_GOLD_KEY 8
1377 #define SPAWNFLAGS_SILVER_KEY 16
1378 void spawnfunc_func_door()
1380 // Quake 1 keys compatibility
1381 if (self.spawnflags & SPAWNFLAGS_GOLD_KEY)
1382 self.itemkeys |= ITEM_KEY_BIT(0);
1383 if (self.spawnflags & SPAWNFLAGS_SILVER_KEY)
1384 self.itemkeys |= ITEM_KEY_BIT(1);
1386 //if (!self.deathtype) // map makers can override this
1387 // self.deathtype = " got in the way";
1390 self.max_health = self.health;
1391 if not(InitMovingBrushTrigger())
1393 self.effects |= EF_LOWPRECISION;
1394 self.classname = "door";
1396 self.blocked = door_blocked;
1397 self.use = door_use;
1399 // FIXME: undocumented flag 8, originally (Q1) GOLD_KEY
1400 // if(self.spawnflags & 8)
1401 // self.dmg = 10000;
1403 if(self.dmg && (!self.message))
1404 self.message = "was squished";
1405 if(self.dmg && (!self.message2))
1406 self.message2 = "was squished by";
1408 if (self.sounds > 0)
1410 precache_sound ("plats/medplat1.wav");
1411 precache_sound ("plats/medplat2.wav");
1412 self.noise2 = "plats/medplat1.wav";
1413 self.noise1 = "plats/medplat2.wav";
1423 self.pos1 = self.origin;
1424 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
1426 // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
1427 // but spawn in the open position
1428 if (self.spawnflags & DOOR_START_OPEN)
1429 InitializeEntity(self, door_init_startopen, INITPRIO_SETLOCATION);
1431 self.state = STATE_BOTTOM;
1435 self.takedamage = DAMAGE_YES;
1436 self.event_damage = door_damage;
1442 self.touch = door_touch;
1444 // LinkDoors can't be done until all of the doors have been spawned, so
1445 // the sizes can be detected properly.
1446 InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
1448 self.reset = door_reset;
1451 /*QUAKED spawnfunc_func_door_rotating (0 .5 .8) ? START_OPEN BIDIR DOOR_DONT_LINK BIDIR_IN_DOWN x TOGGLE X_AXIS Y_AXIS
1452 if two doors touch, they are assumed to be connected and operate as a unit.
1454 TOGGLE causes the door to wait in both the start and end states for a trigger event.
1456 BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor.
1457 The usage of bidirectional doors requires two manually instantiated triggers (trigger_multiple), the one to open it in the other direction
1458 must have set trigger_reverse to 1.
1459 BIDIR_IN_DOWN will the door prevent from reopening while closing if it is triggered from the other side.
1461 START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
1463 "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
1464 "angle" determines the destination angle for opening. negative values reverse the direction.
1465 "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
1466 "health" if set, door must be shot open
1467 "speed" movement speed (100 default)
1468 "wait" wait before returning (3 default, -1 = never return)
1469 "dmg" damage to inflict when blocked (2 default)
1476 FIXME: only one sound set available at the time being
1479 void door_rotating_reset()
1481 self.angles = self.pos1;
1482 self.avelocity = '0 0 0';
1483 self.state = STATE_BOTTOM;
1484 self.think = SUB_Null;
1487 void door_rotating_init_startopen()
1489 self.angles = self.movedir;
1490 self.pos2 = '0 0 0';
1491 self.pos1 = self.movedir;
1495 void spawnfunc_func_door_rotating()
1498 //if (!self.deathtype) // map makers can override this
1499 // self.deathtype = " got in the way";
1501 // I abuse "movedir" for denoting the axis for now
1502 if (self.spawnflags & 64) // X (untested)
1503 self.movedir = '0 0 1';
1504 else if (self.spawnflags & 128) // Y (untested)
1505 self.movedir = '1 0 0';
1507 self.movedir = '0 1 0';
1509 if (self.angles_y==0) self.angles_y = 90;
1511 self.movedir = self.movedir * self.angles_y;
1512 self.angles = '0 0 0';
1514 self.max_health = self.health;
1515 self.avelocity = self.movedir;
1516 if not(InitMovingBrushTrigger())
1518 self.velocity = '0 0 0';
1519 //self.effects |= EF_LOWPRECISION;
1520 self.classname = "door_rotating";
1522 self.blocked = door_blocked;
1523 self.use = door_use;
1525 if(self.spawnflags & 8)
1528 if(self.dmg && (!self.message))
1529 self.message = "was squished";
1530 if(self.dmg && (!self.message2))
1531 self.message2 = "was squished by";
1533 if (self.sounds > 0)
1535 precache_sound ("plats/medplat1.wav");
1536 precache_sound ("plats/medplat2.wav");
1537 self.noise2 = "plats/medplat1.wav";
1538 self.noise1 = "plats/medplat2.wav";
1545 self.lip = 0; // self.lip is used to remember reverse opening direction for door_rotating
1547 self.pos1 = '0 0 0';
1548 self.pos2 = self.movedir;
1550 // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
1551 // but spawn in the open position
1552 if (self.spawnflags & DOOR_START_OPEN)
1553 InitializeEntity(self, door_rotating_init_startopen, INITPRIO_SETLOCATION);
1555 self.state = STATE_BOTTOM;
1559 self.takedamage = DAMAGE_YES;
1560 self.event_damage = door_damage;
1566 self.touch = door_touch;
1568 // LinkDoors can't be done until all of the doors have been spawned, so
1569 // the sizes can be detected properly.
1570 InitializeEntity(self, LinkDoors, INITPRIO_LINKDOORS);
1572 self.reset = door_rotating_reset;
1576 =============================================================================
1580 =============================================================================
1583 void() fd_secret_move1;
1584 void() fd_secret_move2;
1585 void() fd_secret_move3;
1586 void() fd_secret_move4;
1587 void() fd_secret_move5;
1588 void() fd_secret_move6;
1589 void() fd_secret_done;
1591 float SECRET_OPEN_ONCE = 1; // stays open
1592 float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
1593 float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
1594 float SECRET_NO_SHOOT = 8; // only opened by trigger
1595 float SECRET_YES_SHOOT = 16; // shootable even if targeted
1598 void fd_secret_use()
1601 string message_save;
1603 self.health = 10000;
1604 self.bot_attack = TRUE;
1606 // exit if still moving around...
1607 if (self.origin != self.oldorigin)
1610 message_save = self.message;
1611 self.message = ""; // no more message
1612 SUB_UseTargets(); // fire all targets / killtargets
1613 self.message = message_save;
1615 self.velocity = '0 0 0';
1617 // Make a sound, wait a little...
1619 if (self.noise1 != "")
1620 sound(self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTN_NORM);
1621 self.nextthink = self.ltime + 0.1;
1623 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
1624 makevectors(self.mangle);
1628 if (self.spawnflags & SECRET_1ST_DOWN)
1629 self.t_width = fabs(v_up * self.size);
1631 self.t_width = fabs(v_right * self.size);
1635 self.t_length = fabs(v_forward * self.size);
1637 if (self.spawnflags & SECRET_1ST_DOWN)
1638 self.dest1 = self.origin - v_up * self.t_width;
1640 self.dest1 = self.origin + v_right * (self.t_width * temp);
1642 self.dest2 = self.dest1 + v_forward * self.t_length;
1643 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
1644 if (self.noise2 != "")
1645 sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
1648 // Wait after first movement...
1649 void fd_secret_move1()
1651 self.nextthink = self.ltime + 1.0;
1652 self.think = fd_secret_move2;
1653 if (self.noise3 != "")
1654 sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
1657 // Start moving sideways w/sound...
1658 void fd_secret_move2()
1660 if (self.noise2 != "")
1661 sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
1662 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
1665 // Wait here until time to go back...
1666 void fd_secret_move3()
1668 if (self.noise3 != "")
1669 sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
1670 if (!(self.spawnflags & SECRET_OPEN_ONCE))
1672 self.nextthink = self.ltime + self.wait;
1673 self.think = fd_secret_move4;
1678 void fd_secret_move4()
1680 if (self.noise2 != "")
1681 sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
1682 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
1686 void fd_secret_move5()
1688 self.nextthink = self.ltime + 1.0;
1689 self.think = fd_secret_move6;
1690 if (self.noise3 != "")
1691 sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
1694 void fd_secret_move6()
1696 if (self.noise2 != "")
1697 sound(self, CH_TRIGGER_SINGLE, self.noise2, VOL_BASE, ATTN_NORM);
1698 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
1701 void fd_secret_done()
1703 if (self.spawnflags&SECRET_YES_SHOOT)
1705 self.health = 10000;
1706 self.takedamage = DAMAGE_YES;
1707 //self.th_pain = fd_secret_use;
1709 if (self.noise3 != "")
1710 sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NORM);
1713 void secret_blocked()
1715 if (time < self.attack_finished_single)
1717 self.attack_finished_single = time + 0.5;
1718 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
1730 if not(other.iscreature)
1732 if (self.attack_finished_single > time)
1735 self.attack_finished_single = time + 2;
1739 if (other.flags & FL_CLIENT)
1740 centerprint (other, self.message);
1741 play2(other, "misc/talk.wav");
1747 if (self.spawnflags&SECRET_YES_SHOOT)
1749 self.health = 10000;
1750 self.takedamage = DAMAGE_YES;
1752 setorigin(self, self.oldorigin);
1753 self.think = SUB_Null;
1756 /*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
1757 Basic secret door. Slides back, then to the side. Angle determines direction.
1758 wait = # of seconds before coming back
1759 1st_left = 1st move is left of arrow
1760 1st_down = 1st move is down from arrow
1761 always_shoot = even if targeted, keep shootable
1762 t_width = override WIDTH to move back (or height if going down)
1763 t_length = override LENGTH to move sideways
1764 "dmg" damage to inflict when blocked (2 default)
1766 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
1773 void spawnfunc_func_door_secret()
1775 /*if (!self.deathtype) // map makers can override this
1776 self.deathtype = " got in the way";*/
1782 self.mangle = self.angles;
1783 self.angles = '0 0 0';
1784 self.classname = "door";
1785 if not(InitMovingBrushTrigger())
1787 self.effects |= EF_LOWPRECISION;
1789 self.touch = secret_touch;
1790 self.blocked = secret_blocked;
1792 self.use = fd_secret_use;
1797 self.spawnflags |= SECRET_YES_SHOOT;
1799 if(self.spawnflags&SECRET_YES_SHOOT)
1801 self.health = 10000;
1802 self.takedamage = DAMAGE_YES;
1803 self.event_damage = fd_secret_use;
1805 self.oldorigin = self.origin;
1807 self.wait = 5; // 5 seconds before closing
1809 self.reset = secret_reset;
1813 /*QUAKED spawnfunc_func_fourier (0 .5 .8) ?
1814 Brush model that moves in a pattern of added up sine waves, can be used e.g. for circular motions.
1815 netname: list of <frequencymultiplier> <phase> <x> <y> <z> quadruples, separated by spaces; note that phase 0 represents a sine wave, and phase 0.25 a cosine wave (by default, it uses 1 0 0 0 1, to match func_bobbing's defaults
1816 speed: how long one cycle of frequency multiplier 1 in seconds (default 4)
1817 height: amplitude modifier (default 32)
1818 phase: cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
1819 noise: path/name of looping .wav file to play.
1820 dmg: Do this mutch dmg every .dmgtime intervall when blocked
1824 void func_fourier_controller_think()
1829 self.nextthink = time + 0.1;
1830 if not (self.owner.active == ACTIVE_ACTIVE)
1832 self.owner.velocity = '0 0 0';
1837 n = floor((tokenize_console(self.owner.netname)) / 5);
1838 t = self.nextthink * self.owner.cnt + self.owner.phase * 360;
1840 v = self.owner.destvec;
1842 for(i = 0; i < n; ++i)
1844 makevectors((t * stof(argv(i*5)) + stof(argv(i*5+1)) * 360) * '0 1 0');
1845 v = v + ('1 0 0' * stof(argv(i*5+2)) + '0 1 0' * stof(argv(i*5+3)) + '0 0 1' * stof(argv(i*5+4))) * self.owner.height * v_forward_y;
1848 if(self.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed
1849 // * 10 so it will arrive in 0.1 sec
1850 self.owner.velocity = (v - self.owner.origin) * 10;
1853 void spawnfunc_func_fourier()
1856 if (self.noise != "")
1858 precache_sound(self.noise);
1859 soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
1866 self.destvec = self.origin;
1867 self.cnt = 360 / self.speed;
1869 self.blocked = generic_plat_blocked;
1870 if(self.dmg & (!self.message))
1871 self.message = " was squished";
1872 if(self.dmg && (!self.message2))
1873 self.message2 = "was squished by";
1874 if(self.dmg && (!self.dmgtime))
1875 self.dmgtime = 0.25;
1876 self.dmgtime2 = time;
1878 if(self.netname == "")
1879 self.netname = "1 0 0 0 1";
1881 if not(InitMovingBrushTrigger())
1884 self.active = ACTIVE_ACTIVE;
1886 // wait for targets to spawn
1887 controller = spawn();
1888 controller.classname = "func_fourier_controller";
1889 controller.owner = self;
1890 controller.nextthink = time + 1;
1891 controller.think = func_fourier_controller_think;
1892 self.nextthink = self.ltime + 999999999;
1893 self.think = SUB_Null;
1895 // Savage: Reduce bandwith, critical on e.g. nexdm02
1896 self.effects |= EF_LOWPRECISION;
1898 // TODO make a reset function for this one
1901 // reusing some fields havocbots declared
1902 .entity wp00, wp01, wp02, wp03;
1904 .float targetfactor, target2factor, target3factor, target4factor;
1905 .vector targetnormal, target2normal, target3normal, target4normal;
1907 vector func_vectormamamam_origin(entity o, float t)
1919 p = e.origin + t * e.velocity;
1921 v = v + (p * o.targetnormal) * o.targetnormal * o.targetfactor;
1923 v = v + (p - (p * o.targetnormal) * o.targetnormal) * o.targetfactor;
1929 p = e.origin + t * e.velocity;
1931 v = v + (p * o.target2normal) * o.target2normal * o.target2factor;
1933 v = v + (p - (p * o.target2normal) * o.target2normal) * o.target2factor;
1939 p = e.origin + t * e.velocity;
1941 v = v + (p * o.target3normal) * o.target3normal * o.target3factor;
1943 v = v + (p - (p * o.target3normal) * o.target3normal) * o.target3factor;
1949 p = e.origin + t * e.velocity;
1951 v = v + (p * o.target4normal) * o.target4normal * o.target4factor;
1953 v = v + (p - (p * o.target4normal) * o.target4normal) * o.target4factor;
1959 void func_vectormamamam_controller_think()
1961 self.nextthink = time + 0.1;
1963 if not (self.owner.active == ACTIVE_ACTIVE)
1965 self.owner.velocity = '0 0 0';
1969 if(self.owner.classname == "func_vectormamamam") // don't brake stuff if the func_vectormamamam was killtarget'ed
1970 self.owner.velocity = (self.owner.destvec + func_vectormamamam_origin(self.owner, 0.1) - self.owner.origin) * 10;
1973 void func_vectormamamam_findtarget()
1975 if(self.target != "")
1976 self.wp00 = find(world, targetname, self.target);
1978 if(self.target2 != "")
1979 self.wp01 = find(world, targetname, self.target2);
1981 if(self.target3 != "")
1982 self.wp02 = find(world, targetname, self.target3);
1984 if(self.target4 != "")
1985 self.wp03 = find(world, targetname, self.target4);
1987 if(!self.wp00 && !self.wp01 && !self.wp02 && !self.wp03)
1988 objerror("No reference entity found, so there is nothing to move. Aborting.");
1990 self.destvec = self.origin - func_vectormamamam_origin(self.owner, 0);
1993 controller = spawn();
1994 controller.classname = "func_vectormamamam_controller";
1995 controller.owner = self;
1996 controller.nextthink = time + 1;
1997 controller.think = func_vectormamamam_controller_think;
2000 void spawnfunc_func_vectormamamam()
2002 if (self.noise != "")
2004 precache_sound(self.noise);
2005 soundto(MSG_INIT, self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTN_IDLE);
2008 if(!self.targetfactor)
2009 self.targetfactor = 1;
2011 if(!self.target2factor)
2012 self.target2factor = 1;
2014 if(!self.target3factor)
2015 self.target3factor = 1;
2017 if(!self.target4factor)
2018 self.target4factor = 1;
2020 if(vlen(self.targetnormal))
2021 self.targetnormal = normalize(self.targetnormal);
2023 if(vlen(self.target2normal))
2024 self.target2normal = normalize(self.target2normal);
2026 if(vlen(self.target3normal))
2027 self.target3normal = normalize(self.target3normal);
2029 if(vlen(self.target4normal))
2030 self.target4normal = normalize(self.target4normal);
2032 self.blocked = generic_plat_blocked;
2033 if(self.dmg & (!self.message))
2034 self.message = " was squished";
2035 if(self.dmg && (!self.message2))
2036 self.message2 = "was squished by";
2037 if(self.dmg && (!self.dmgtime))
2038 self.dmgtime = 0.25;
2039 self.dmgtime2 = time;
2041 if(self.netname == "")
2042 self.netname = "1 0 0 0 1";
2044 if not(InitMovingBrushTrigger())
2047 // wait for targets to spawn
2048 self.nextthink = self.ltime + 999999999;
2049 self.think = SUB_Null;
2051 // Savage: Reduce bandwith, critical on e.g. nexdm02
2052 self.effects |= EF_LOWPRECISION;
2054 self.active = ACTIVE_ACTIVE;
2056 InitializeEntity(self, func_vectormamamam_findtarget, INITPRIO_FINDTARGET);