3 float STATE_BOTTOM = 1;
11 void() plat_center_touch;
12 void() plat_outside_touch;
13 void() plat_trigger_use;
17 float PLAT_LOW_TRIGGER = 1;
19 void() plat_spawn_inside_trigger =
22 local vector tmin, tmax;
25 trigger.touch = plat_center_touch;
26 trigger.movetype = MOVETYPE_NONE;
27 trigger.solid = SOLID_TRIGGER;
30 tmin = self.mins + '25 25 0';
31 tmax = self.maxs - '25 25 -8';
32 tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
33 if (self.spawnflags & PLAT_LOW_TRIGGER)
36 if (self.size_x <= 50)
38 tmin_x = (self.mins_x + self.maxs_x) / 2;
41 if (self.size_y <= 50)
43 tmin_y = (self.mins_y + self.maxs_y) / 2;
47 setsize (trigger, tmin, tmax);
52 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
54 self.think = plat_go_down;
55 self.nextthink = self.ltime + 3;
58 void() plat_hit_bottom =
60 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
66 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
68 SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
73 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
75 SUB_CalcMove (self.pos1, self.speed, plat_hit_top);
78 void() plat_center_touch =
80 if (other.classname != "player")
83 if (other.health <= 0)
89 else if (self.state == 1)
90 self.nextthink = self.ltime + 1; // delay going down
93 void() plat_outside_touch =
95 if (other.classname != "player")
98 if (other.health <= 0)
106 void() plat_trigger_use =
109 return; // allready activated
116 if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
117 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
119 if((self.dmg) && (other.takedamage != DAMAGE_NO)) { // Shall we bite?
120 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
121 // Gib dead/dying stuff
122 if(other.deadflag != DEAD_NO)
123 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
128 else if (self.state == 3)
131 objerror ("plat_crush: bad self.state\n");
139 objerror ("plat_use: not in up state");
144 .string sound1, sound2;
153 if (self.sounds == 0)
156 if(self.spawnflags & 4)
159 if(self.dmg && (!self.message))
160 self.message = "was in the wrong place.";
162 if (self.sounds == 1)
164 precache_sound ("plats/plat1.wav");
165 precache_sound ("plats/plat2.wav");
166 self.noise = "plats/plat1.wav";
167 self.noise1 = "plats/plat2.wav";
170 if (self.sounds == 2)
172 precache_sound ("plats/medplat1.wav");
173 precache_sound ("plats/medplat2.wav");
174 self.noise = "plats/medplat1.wav";
175 self.noise1 = "plats/medplat2.wav";
180 precache_sound (self.sound1);
181 self.noise = self.sound1;
185 precache_sound (self.sound2);
186 self.noise1 = self.sound2;
189 self.mangle = self.angles;
190 self.angles = '0 0 0';
192 self.classname = "plat";
193 self.solid = SOLID_BSP;
194 self.movetype = MOVETYPE_PUSH;
195 setorigin (self, self.origin);
196 setmodel (self, self.model);
197 setsize (self, self.mins , self.maxs);
199 self.blocked = plat_crush;
204 self.pos1 = self.origin;
205 self.pos2 = self.origin;
206 self.pos2_z = self.origin_z - self.size_z + 8;
208 self.use = plat_trigger_use;
210 plat_spawn_inside_trigger (); // the "start moving" trigger
219 setorigin (self, self.pos2);
227 void() func_train_find;
229 void() train_blocked =
231 if (time < self.attack_finished)
233 self.attack_finished = time + 0.5;
237 if (self.think != func_train_find)
246 self.nextthink = self.ltime + self.wait;
247 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
250 self.nextthink = self.ltime + 0.1;
252 self.think = train_next;
259 targ = find (world, targetname, self.target);
260 self.target = targ.target;
262 objerror ("train_next: no next target");
264 self.wait = targ.wait;
267 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
268 SUB_CalcMove (targ.origin - self.mins, self.speed, train_wait);
271 void() func_train_find =
275 targ = find (world, targetname, self.target);
276 self.target = targ.target;
277 setorigin (self, targ.origin - self.mins);
278 if (!self.targetname)
279 { // not triggered, so start immediately
280 self.nextthink = self.ltime + 0.1;
281 self.think = train_next;
291 objerror ("func_train without a target");
293 if (self.sounds == 0)
295 self.noise = ("misc/null.wav");
296 precache_sound ("misc/null.wav");
297 self.noise1 = ("misc/null.wav");
298 precache_sound ("misc/null.wav");
301 if (self.sounds == 1)
303 self.noise = ("plats/train2.wav");
304 precache_sound ("plats/train2.wav");
305 self.noise1 = ("plats/train1.wav");
306 precache_sound ("plats/train1.wav");
309 self.solid = SOLID_BSP;
310 self.movetype = MOVETYPE_PUSH;
311 self.blocked = train_blocked;
312 self.use = train_use;
313 self.classname = "train";
315 setmodel (self, self.model);
316 setsize (self, self.mins , self.maxs);
317 setorigin (self, self.origin);
318 self.nextthink = self.ltime + 0.1;
319 self.think = func_train_find;
326 self.think = train_next;
327 self.nextthink = self.ltime + self.wait;
333 targ = find(world, targetname, self.target);
334 self.target = targ.target;
336 objerror("train_next: no next target");
337 self.wait = targ.wait;
341 SUB_CalcMove(targ.origin - self.mins, targ.speed, train_wait);
343 SUB_CalcMove(targ.origin - self.mins, self.speed, train_wait);
346 void() func_train_find =
349 targ = find(world, targetname, self.target);
350 self.target = targ.target;
351 setorigin(self, targ.origin - self.mins);
352 self.nextthink = self.ltime + 1;
353 self.think = train_next;
356 /*QUAKED func_train (0 .5 .8) ?
357 Ridable platform, targets path_corner path to follow.
358 speed : speed the train moves (can be overridden by each path_corner)
359 target : targetname of first path_corner (starts here)
364 objerror("func_train without a target");
368 self.solid = SOLID_BSP;
369 self.movetype = MOVETYPE_PUSH;
371 setmodel(self, self.model);
372 setsize(self, self.mins, self.maxs);
373 setorigin(self, self.origin);
375 // wait for targets to spawn
376 self.nextthink = self.ltime + 0.1;
377 self.think = func_train_find;
382 void() rotating_blocked =
385 if(self.dmg && other.takedamage != DAMAGE_NO) {
386 if(self.dmgtime2 < time) {
387 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
388 self.dmgtime2 = time + self.dmgtime;
391 // Gib dead/dying stuff
392 if(other.deadflag != DEAD_NO)
393 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
399 /*QUAKED func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
400 Brush model that spins in place on one axis (default Z).
401 speed : speed to rotate (in degrees per second)
402 noise : path/name of looping .wav file to play.
403 dmg : Do this mutch dmg every .dmgtime intervall when blocked
407 void() func_rotating =
411 precache_sound(self.noise);
412 ambientsound(self.origin, self.noise, 1, ATTN_IDLE);
416 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
417 if (self.spawnflags & 4) // X (untested)
418 self.avelocity = '0 0 1' * self.speed;
419 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
420 else if (self.spawnflags & 8) // Y (untested)
421 self.avelocity = '1 0 0' * self.speed;
422 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
424 self.avelocity = '0 1 0' * self.speed;
426 if(self.dmg & (!self.message))
427 self.message = " was in the wrong place.";
430 if(self.dmg && (!self.dmgtime))
433 self.dmgtime2 = time;
436 self.solid = SOLID_BSP;
437 self.movetype = MOVETYPE_PUSH;
439 setmodel(self, self.model);
440 setsize(self, self.mins, self.maxs);
441 setorigin(self, self.origin);
443 self.blocked = rotating_blocked;
445 // wait for targets to spawn
446 self.nextthink = self.ltime + 999999999;
447 self.think = SUB_Null;
452 void() func_bobbing_controller_think =
455 self.nextthink = time + 0.1;
456 // calculate sinewave using makevectors
457 makevectors((time * self.owner.cnt + self.owner.phase) * '0 1 0');
458 v = self.owner.destvec + self.owner.movedir * v_forward_y;
459 // * 10 so it will arrive in 0.1 sec
460 self.owner.velocity = (v - self.owner.origin) * 10;
463 /*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
464 Brush model that moves back and forth on one axis (default Z).
465 speed : how long one cycle takes in seconds (default 4)
466 height : how far the cycle moves (default 32)
467 phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
468 noise : path/name of looping .wav file to play.
470 void() func_bobbing =
472 local entity controller;
475 precache_sound(self.noise);
476 ambientsound(self.origin, self.noise, 1, ATTN_IDLE);
482 // center of bobbing motion
483 self.destvec = self.origin;
484 // time scale to get degrees
485 self.cnt = 360 / self.speed;
487 if (self.spawnflags & 1) // X
488 self.movedir = '1 0 0' * self.height;
489 else if (self.spawnflags & 2) // Y
490 self.movedir = '0 1 0' * self.height;
492 self.movedir = '0 0 1' * self.height;
494 self.solid = SOLID_BSP;
495 self.movetype = MOVETYPE_PUSH;
497 setmodel(self, self.model);
498 setsize(self, self.mins, self.maxs);
499 setorigin(self, self.origin);
501 // wait for targets to spawn
502 controller = spawn();
503 controller.classname = "func_bobbing_controller";
504 controller.owner = self;
505 controller.nextthink = time + 1;
506 controller.think = func_bobbing_controller_think;
507 self.nextthink = self.ltime + 999999999;
508 self.think = SUB_Null;
510 // Savage: Reduce bandwith, critical on e.g. nexdm02
511 self.effects |= EF_LOWPRECISION;
514 // button and multiple button
517 void() button_return;
521 self.state = STATE_TOP;
522 self.nextthink = self.ltime + self.wait;
523 self.think = button_return;
524 activator = self.enemy;
526 self.frame = 1; // use alternate textures
531 self.state = STATE_BOTTOM;
534 void() button_return =
536 self.state = STATE_DOWN;
537 SUB_CalcMove (self.pos1, self.speed, button_done);
538 self.frame = 0; // use normal textures
540 self.takedamage = DAMAGE_YES; // can be shot again
544 void() button_blocked =
546 // do nothing, just don't come all the way back out
552 self.health = self.max_health;
553 self.takedamage = DAMAGE_NO; // will be reset upon return
555 if (self.state == STATE_UP || self.state == STATE_TOP)
558 if (self.noise != "")
559 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
561 self.state = STATE_UP;
562 SUB_CalcMove (self.pos2, self.speed, button_wait);
568 // if (activator.classname != "player")
570 // dprint(activator.classname);
571 // dprint(" triggered a button\n");
573 self.enemy = activator;
577 void() button_touch =
579 // if (activator.classname != "player")
581 // dprint(activator.classname);
582 // dprint(" touched a button\n");
586 if (other.classname != "player")
590 self.enemy = other.owner;
594 void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) button_damage =
596 self.health = self.health - damage;
597 if (self.health <= 0)
599 // if (activator.classname != "player")
601 // dprint(activator.classname);
602 // dprint(" killed a button\n");
604 self.enemy = damage_attacker;
610 /*QUAKED func_button (0 .5 .8) ?
611 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.
613 "angle" determines the opening direction
614 "target" all entities with a matching targetname will be used
615 "speed" override the default 40 speed
616 "wait" override the default 1 second wait (-1 = never return)
617 "lip" override the default 4 pixel lip remaining at end of move
618 "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
629 self.movetype = MOVETYPE_PUSH;
630 self.solid = SOLID_BSP;
631 setmodel (self, self.model);
633 self.blocked = button_blocked;
634 self.use = button_use;
636 // if (self.health == 0) // all buttons are now shootable
640 self.max_health = self.health;
641 self.event_damage = button_damage;
642 self.takedamage = DAMAGE_YES;
645 self.touch = button_touch;
654 self.state = STATE_BOTTOM;
656 self.pos1 = self.origin;
657 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
661 float DOOR_START_OPEN = 1;
662 float DOOR_DONT_LINK = 4;
663 float DOOR_TOGGLE = 32;
667 Doors are similar to buttons, but can spawn a fat trigger field around them
668 to open without a touch, and they link together to form simultanious
671 Door.owner is the master door. If there is only one door, it points to itself.
672 If multiple doors, all will point to a single one.
674 Door.enemy chains from the master door through all doors linked in the chain.
679 =============================================================================
683 =============================================================================
689 void() door_blocked =
692 if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
693 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
696 if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
697 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
699 //Dont chamge direction for dead or dying stuff
700 if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
703 if (self.state == STATE_DOWN)
709 //gib dying stuff just to make sure
710 if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
711 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
715 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
716 // if a door has a negative wait, it would never come back if blocked,
717 // so let it just squash the object to death real fast
718 /* if (self.wait >= 0)
720 if (self.state == STATE_DOWN)
729 void() door_hit_top =
731 if (self.noise1 != "")
732 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
733 self.state = STATE_TOP;
734 if (self.spawnflags & DOOR_TOGGLE)
735 return; // don't come down automatically
736 self.think = door_go_down;
737 self.nextthink = self.ltime + self.wait;
740 void() door_hit_bottom =
742 if (self.noise1 != "")
743 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
744 self.state = STATE_BOTTOM;
747 void() door_go_down =
749 if (self.noise2 != "")
750 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
753 self.takedamage = DAMAGE_YES;
754 self.health = self.max_health;
757 self.state = STATE_DOWN;
758 SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
763 if (self.state == STATE_UP)
764 return; // allready going up
766 if (self.state == STATE_TOP)
767 { // reset top wait time
768 self.nextthink = self.ltime + self.wait;
772 if (self.noise2 != "")
773 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
774 self.state = STATE_UP;
775 SUB_CalcMove (self.pos2, self.speed, door_hit_top);
782 =============================================================================
786 =============================================================================
794 if (self.owner != self)
795 objerror ("door_fire: self.owner != self");
797 self.message = ""; // no more message
800 if (self.spawnflags & DOOR_TOGGLE)
802 if (self.state == STATE_UP || self.state == STATE_TOP)
809 } while ( (self != starte) && (self != world) );
815 // trigger all paired doors
821 } while ( (self != starte) && (self != world) );
830 //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
831 self.message = ""; // door message are for touch only
833 self.owner.message = "";
835 self.enemy.message = "";
846 void() door_trigger_touch =
848 if (other.health < 1)
851 if (time < self.attack_finished)
853 self.attack_finished = time + 1;
862 void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) door_damage =
865 self.health = self.health - damage;
866 if (self.health <= 0)
870 self.health = self.max_health;
871 self.takedamage = DAMAGE_NO; // wil be reset upon return
887 if (other.classname != "player")
889 if (self.owner.attack_finished > time)
892 self.owner.attack_finished = time + 2;
894 if (self.owner.message != "")
896 if (other.flags & FL_CLIENT)
897 centermsg_setfor (other, CENTERMSG_TRIGGER, self.owner.message);
898 sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
903 =============================================================================
907 =============================================================================
911 entity(vector fmins, vector fmaxs) spawn_field =
913 local entity trigger;
917 trigger.classname = "doortriggerfield";
918 trigger.movetype = MOVETYPE_NONE;
919 trigger.solid = SOLID_TRIGGER;
920 trigger.owner = self;
921 trigger.touch = door_trigger_touch;
925 setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
930 float (entity e1, entity e2) EntitiesTouching =
932 if (e1.mins_x > e2.maxs_x)
934 if (e1.mins_y > e2.maxs_y)
936 if (e1.mins_z > e2.maxs_z)
938 if (e1.maxs_x < e2.mins_x)
940 if (e1.maxs_y < e2.mins_y)
942 if (e1.maxs_z < e2.mins_z)
957 local entity t, starte;
958 local vector cmins, cmaxs;
961 return; // already linked by another door
962 if (self.spawnflags & 4)
964 self.owner = self.enemy = self;
965 return; // don't want to link this door
976 self.owner = starte; // master door
979 starte.health = self.health;
981 starte.targetname = self.targetname;
982 if (self.message != "")
983 starte.message = self.message;
985 t = find(t, classname, self.classname);
988 self.enemy = starte; // make the chain a loop
990 // shootable, or triggered doors just needed the owner/enemy links,
991 // they don't spawn a field
1002 self.owner.trigger_field = spawn_field(cmins, cmaxs);
1007 if (EntitiesTouching(self,t))
1010 objerror ("cross connected doors");
1015 if (t.mins_x < cmins_x)
1017 if (t.mins_y < cmins_y)
1019 if (t.mins_z < cmins_z)
1021 if (t.maxs_x > cmaxs_x)
1023 if (t.maxs_y > cmaxs_y)
1025 if (t.maxs_z > cmaxs_z)
1033 /*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK x x TOGGLE
1034 if two doors touch, they are assumed to be connected and operate as a unit.
1036 TOGGLE causes the door to wait in both the start and end states for a trigger event.
1038 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).
1040 "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
1041 "angle" determines the opening direction
1042 "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
1043 "health" if set, door must be shot open
1044 "speed" movement speed (100 default)
1045 "wait" wait before returning (3 default, -1 = never return)
1046 "lip" lip remaining at end of move (8 default)
1047 "dmg" damage to inflict when blocked (2 default)
1054 FIXME: only one sound set available at the time being
1060 //if (!self.deathtype) // map makers can override this
1061 // self.deathtype = " got in the way";
1064 self.max_health = self.health;
1065 self.solid = SOLID_BSP;
1066 self.movetype = MOVETYPE_PUSH;
1067 setorigin (self, self.origin);
1068 setmodel (self, self.model);
1069 self.classname = "door";
1071 self.blocked = door_blocked;
1072 self.use = door_use;
1074 if(self.targetname == "") {
1075 self.spawnflags = 0;
1079 if(self.spawnflags & 4)
1082 if(self.dmg & (!self.message))
1083 self.message = "was in the wrong place.";
1087 if (self.sounds > 0)
1089 precache_sound ("plats/medplat1.wav");
1090 precache_sound ("plats/medplat2.wav");
1091 self.noise2 = "plats/medplat1.wav";
1092 self.noise1 = "plats/medplat2.wav";
1104 self.pos1 = self.origin;
1105 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
1107 // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
1108 // but spawn in the open position
1109 if (self.spawnflags & DOOR_START_OPEN)
1111 setorigin (self, self.pos2);
1112 self.pos2 = self.pos1;
1113 self.pos1 = self.origin;
1116 self.state = STATE_BOTTOM;
1120 self.takedamage = DAMAGE_YES;
1121 self.event_damage = door_damage;
1127 self.touch = door_touch;
1129 // LinkDoors can't be done until all of the doors have been spawned, so
1130 // the sizes can be detected properly.
1131 self.think = LinkDoors;
1132 self.nextthink = self.ltime + 0.1;
1136 =============================================================================
1140 =============================================================================
1143 void() fd_secret_move1;
1144 void() fd_secret_move2;
1145 void() fd_secret_move3;
1146 void() fd_secret_move4;
1147 void() fd_secret_move5;
1148 void() fd_secret_move6;
1149 void() fd_secret_done;
1151 float SECRET_OPEN_ONCE = 1; // stays open
1152 float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
1153 float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
1154 float SECRET_NO_SHOOT = 8; // only opened by trigger
1155 float SECRET_YES_SHOOT = 16; // shootable even if targeted
1158 void () fd_secret_use =
1162 self.health = 10000;
1163 self.bot_attack = TRUE;
1165 // exit if still moving around...
1166 if (self.origin != self.oldorigin)
1169 self.message = ""; // no more message
1171 SUB_UseTargets(); // fire all targets / killtargets
1173 self.velocity = '0 0 0';
1175 // Make a sound, wait a little...
1177 if (self.noise1 != "")
1178 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
1179 self.nextthink = self.ltime + 0.1;
1181 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
1182 makevectors(self.mangle);
1186 if (self.spawnflags & SECRET_1ST_DOWN)
1187 self.t_width = fabs(v_up * self.size);
1189 self.t_width = fabs(v_right * self.size);
1193 self.t_length = fabs(v_forward * self.size);
1195 if (self.spawnflags & SECRET_1ST_DOWN)
1196 self.dest1 = self.origin - v_up * self.t_width;
1198 self.dest1 = self.origin + v_right * (self.t_width * temp);
1200 self.dest2 = self.dest1 + v_forward * self.t_length;
1201 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
1202 if (self.noise2 != "")
1203 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1206 // Wait after first movement...
1207 void () fd_secret_move1 =
1209 self.nextthink = self.ltime + 1.0;
1210 self.think = fd_secret_move2;
1211 if (self.noise3 != "")
1212 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1215 // Start moving sideways w/sound...
1216 void () fd_secret_move2 =
1218 if (self.noise2 != "")
1219 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1220 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
1223 // Wait here until time to go back...
1224 void () fd_secret_move3 =
1226 if (self.noise3 != "")
1227 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1228 if (!(self.spawnflags & SECRET_OPEN_ONCE))
1230 self.nextthink = self.ltime + self.wait;
1231 self.think = fd_secret_move4;
1236 void () fd_secret_move4 =
1238 if (self.noise2 != "")
1239 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1240 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
1244 void () fd_secret_move5 =
1246 self.nextthink = self.ltime + 1.0;
1247 self.think = fd_secret_move6;
1248 if (self.noise3 != "")
1249 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1252 void () fd_secret_move6 =
1254 if (self.noise2 != "")
1255 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1256 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
1259 void () fd_secret_done =
1261 if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
1263 self.health = 10000;
1264 self.takedamage = DAMAGE_YES;
1265 //self.th_pain = fd_secret_use;
1267 if (self.noise3 != "")
1268 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1271 void () secret_blocked =
1273 if (time < self.attack_finished)
1275 self.attack_finished = time + 0.5;
1276 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
1286 void() secret_touch =
1288 if (activator.classname != "player")
1290 if (self.attack_finished > time)
1293 self.attack_finished = time + 2;
1297 if (other.flags & FL_CLIENT)
1298 centermsg_setfor (other, CENTERMSG_TRIGGER, self.message);
1299 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
1304 /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
1305 Basic secret door. Slides back, then to the side. Angle determines direction.
1306 wait = # of seconds before coming back
1307 1st_left = 1st move is left of arrow
1308 1st_down = 1st move is down from arrow
1309 always_shoot = even if targeted, keep shootable
1310 t_width = override WIDTH to move back (or height if going down)
1311 t_length = override LENGTH to move sideways
1312 "dmg" damage to inflict when blocked (2 default)
1314 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
1321 void () func_door_secret =
1323 /*if (!self.deathtype) // map makers can override this
1324 self.deathtype = " got in the way";*/
1330 self.mangle = self.angles;
1331 self.angles = '0 0 0';
1332 self.solid = SOLID_BSP;
1333 self.movetype = MOVETYPE_PUSH;
1334 self.classname = "door";
1335 setmodel (self, self.model);
1336 setorigin (self, self.origin);
1338 self.touch = secret_touch;
1339 self.blocked = secret_blocked;
1341 self.use = fd_secret_use;
1342 if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
1344 self.health = 10000;
1345 self.takedamage = DAMAGE_YES;
1346 self.event_damage = fd_secret_use;
1348 self.oldorigin = self.origin;
1350 self.wait = 5; // 5 seconds before closing