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); // precision set below
197 self.effects |= EF_LOWPRECISION;
198 setsize (self, self.mins , self.maxs);
200 self.blocked = plat_crush;
205 self.pos1 = self.origin;
206 self.pos2 = self.origin;
207 self.pos2_z = self.origin_z - self.size_z + 8;
209 self.use = plat_trigger_use;
211 plat_spawn_inside_trigger (); // the "start moving" trigger
220 setorigin (self, self.pos2);
228 void() func_train_find;
230 void() train_blocked =
232 if (time < self.attack_finished)
234 self.attack_finished = time + 0.5;
238 if (self.think != func_train_find)
247 self.nextthink = self.ltime + self.wait;
248 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
251 self.nextthink = self.ltime + 0.1;
253 self.think = train_next;
260 targ = find (world, targetname, self.target);
261 self.target = targ.target;
263 objerror ("train_next: no next target");
265 self.wait = targ.wait;
268 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
269 SUB_CalcMove (targ.origin - self.mins, self.speed, train_wait);
272 void() func_train_find =
276 targ = find (world, targetname, self.target);
277 self.target = targ.target;
278 setorigin (self, targ.origin - self.mins);
279 if (!self.targetname)
280 { // not triggered, so start immediately
281 self.nextthink = self.ltime + 0.1;
282 self.think = train_next;
292 objerror ("func_train without a target");
294 if (self.sounds == 0)
296 self.noise = ("misc/null.wav");
297 precache_sound ("misc/null.wav");
298 self.noise1 = ("misc/null.wav");
299 precache_sound ("misc/null.wav");
302 if (self.sounds == 1)
304 self.noise = ("plats/train2.wav");
305 precache_sound ("plats/train2.wav");
306 self.noise1 = ("plats/train1.wav");
307 precache_sound ("plats/train1.wav");
310 self.solid = SOLID_BSP;
311 self.movetype = MOVETYPE_PUSH;
312 self.blocked = train_blocked;
313 self.use = train_use;
314 self.classname = "train";
316 setmodel (self, self.model); // precision set below
317 self.effects |= EF_LOWPRECISION;
318 setsize (self, self.mins , self.maxs);
319 setorigin (self, self.origin);
320 self.nextthink = self.ltime + 0.1;
321 self.think = func_train_find;
328 self.think = train_next;
329 self.nextthink = self.ltime + self.wait;
335 targ = find(world, targetname, self.target);
336 self.target = targ.target;
338 objerror("train_next: no next target");
339 self.wait = targ.wait;
343 SUB_CalcMove(targ.origin - self.mins, targ.speed, train_wait);
345 SUB_CalcMove(targ.origin - self.mins, self.speed, train_wait);
348 void() func_train_find =
351 targ = find(world, targetname, self.target);
352 self.target = targ.target;
353 setorigin(self, targ.origin - self.mins);
354 self.nextthink = self.ltime + 1;
355 self.think = train_next;
358 /*QUAKED func_train (0 .5 .8) ?
359 Ridable platform, targets path_corner path to follow.
360 speed : speed the train moves (can be overridden by each path_corner)
361 target : targetname of first path_corner (starts here)
366 objerror("func_train without a target");
370 self.solid = SOLID_BSP;
371 self.movetype = MOVETYPE_PUSH;
373 setmodel(self, self.model); // precision set below
374 self.effects |= EF_LOWPRECISION;
375 setsize(self, self.mins, self.maxs);
376 setorigin(self, self.origin);
378 // wait for targets to spawn
379 self.nextthink = self.ltime + 0.1;
380 self.think = func_train_find;
385 void() rotating_blocked =
388 if(self.dmg && other.takedamage != DAMAGE_NO) {
389 if(self.dmgtime2 < time) {
390 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
391 self.dmgtime2 = time + self.dmgtime;
394 // Gib dead/dying stuff
395 if(other.deadflag != DEAD_NO)
396 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
402 /*QUAKED func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
403 Brush model that spins in place on one axis (default Z).
404 speed : speed to rotate (in degrees per second)
405 noise : path/name of looping .wav file to play.
406 dmg : Do this mutch dmg every .dmgtime intervall when blocked
410 void() func_rotating =
414 precache_sound(self.noise);
415 ambientsound(self.origin, self.noise, 1, ATTN_IDLE);
419 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
420 if (self.spawnflags & 4) // X (untested)
421 self.avelocity = '0 0 1' * self.speed;
422 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
423 else if (self.spawnflags & 8) // Y (untested)
424 self.avelocity = '1 0 0' * self.speed;
425 // FIXME: test if this turns the right way, then remove this comment (negate as needed)
427 self.avelocity = '0 1 0' * self.speed;
429 if(self.dmg & (!self.message))
430 self.message = " was in the wrong place.";
433 if(self.dmg && (!self.dmgtime))
436 self.dmgtime2 = time;
439 self.solid = SOLID_BSP;
440 self.movetype = MOVETYPE_PUSH;
442 setmodel(self, self.model); // no lowprecision here! evil!
443 setsize(self, self.mins, self.maxs);
444 setorigin(self, self.origin);
446 self.blocked = rotating_blocked;
448 // wait for targets to spawn
449 self.nextthink = self.ltime + 999999999;
450 self.think = SUB_Null;
455 void() func_bobbing_controller_think =
458 self.nextthink = time + 0.1;
459 // calculate sinewave using makevectors
460 makevectors((time * self.owner.cnt + self.owner.phase) * '0 1 0');
461 v = self.owner.destvec + self.owner.movedir * v_forward_y;
462 // * 10 so it will arrive in 0.1 sec
463 self.owner.velocity = (v - self.owner.origin) * 10;
466 /*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
467 Brush model that moves back and forth on one axis (default Z).
468 speed : how long one cycle takes in seconds (default 4)
469 height : how far the cycle moves (default 32)
470 phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
471 noise : path/name of looping .wav file to play.
473 void() func_bobbing =
475 local entity controller;
478 precache_sound(self.noise);
479 ambientsound(self.origin, self.noise, 1, ATTN_IDLE);
485 // center of bobbing motion
486 self.destvec = self.origin;
487 // time scale to get degrees
488 self.cnt = 360 / self.speed;
490 if (self.spawnflags & 1) // X
491 self.movedir = '1 0 0' * self.height;
492 else if (self.spawnflags & 2) // Y
493 self.movedir = '0 1 0' * self.height;
495 self.movedir = '0 0 1' * self.height;
497 self.solid = SOLID_BSP;
498 self.movetype = MOVETYPE_PUSH;
500 setmodel(self, self.model); // precision set below
501 setsize(self, self.mins, self.maxs);
502 setorigin(self, self.origin);
504 // wait for targets to spawn
505 controller = spawn();
506 controller.classname = "func_bobbing_controller";
507 controller.owner = self;
508 controller.nextthink = time + 1;
509 controller.think = func_bobbing_controller_think;
510 self.nextthink = self.ltime + 999999999;
511 self.think = SUB_Null;
513 // Savage: Reduce bandwith, critical on e.g. nexdm02
514 self.effects |= EF_LOWPRECISION;
517 // button and multiple button
520 void() button_return;
524 self.state = STATE_TOP;
525 self.nextthink = self.ltime + self.wait;
526 self.think = button_return;
527 activator = self.enemy;
529 self.frame = 1; // use alternate textures
534 self.state = STATE_BOTTOM;
537 void() button_return =
539 self.state = STATE_DOWN;
540 SUB_CalcMove (self.pos1, self.speed, button_done);
541 self.frame = 0; // use normal textures
543 self.takedamage = DAMAGE_YES; // can be shot again
547 void() button_blocked =
549 // do nothing, just don't come all the way back out
555 self.health = self.max_health;
556 self.takedamage = DAMAGE_NO; // will be reset upon return
558 if (self.state == STATE_UP || self.state == STATE_TOP)
561 if (self.noise != "")
562 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
564 self.state = STATE_UP;
565 SUB_CalcMove (self.pos2, self.speed, button_wait);
571 // if (activator.classname != "player")
573 // dprint(activator.classname);
574 // dprint(" triggered a button\n");
576 self.enemy = activator;
580 void() button_touch =
582 // if (activator.classname != "player")
584 // dprint(activator.classname);
585 // dprint(" touched a button\n");
589 if (other.classname != "player")
593 self.enemy = other.owner;
597 void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) button_damage =
599 self.health = self.health - damage;
600 if (self.health <= 0)
602 // if (activator.classname != "player")
604 // dprint(activator.classname);
605 // dprint(" killed a button\n");
607 self.enemy = damage_attacker;
613 /*QUAKED func_button (0 .5 .8) ?
614 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.
616 "angle" determines the opening direction
617 "target" all entities with a matching targetname will be used
618 "speed" override the default 40 speed
619 "wait" override the default 1 second wait (-1 = never return)
620 "lip" override the default 4 pixel lip remaining at end of move
621 "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
632 self.movetype = MOVETYPE_PUSH;
633 self.solid = SOLID_BSP;
634 setmodel (self, self.model); // precision set below
635 self.effects |= EF_LOWPRECISION;
637 self.blocked = button_blocked;
638 self.use = button_use;
640 // if (self.health == 0) // all buttons are now shootable
644 self.max_health = self.health;
645 self.event_damage = button_damage;
646 self.takedamage = DAMAGE_YES;
649 self.touch = button_touch;
658 self.state = STATE_BOTTOM;
660 self.pos1 = self.origin;
661 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
665 float DOOR_START_OPEN = 1;
666 float DOOR_DONT_LINK = 4;
667 float DOOR_TOGGLE = 32;
671 Doors are similar to buttons, but can spawn a fat trigger field around them
672 to open without a touch, and they link together to form simultanious
675 Door.owner is the master door. If there is only one door, it points to itself.
676 If multiple doors, all will point to a single one.
678 Door.enemy chains from the master door through all doors linked in the chain.
683 =============================================================================
687 =============================================================================
693 void() door_blocked =
696 if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO)) { // KIll Kill Kill!!
697 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
700 if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
701 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
703 //Dont chamge direction for dead or dying stuff
704 if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
707 if (self.state == STATE_DOWN)
713 //gib dying stuff just to make sure
714 if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
715 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
719 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
720 // if a door has a negative wait, it would never come back if blocked,
721 // so let it just squash the object to death real fast
722 /* if (self.wait >= 0)
724 if (self.state == STATE_DOWN)
733 void() door_hit_top =
735 if (self.noise1 != "")
736 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
737 self.state = STATE_TOP;
738 if (self.spawnflags & DOOR_TOGGLE)
739 return; // don't come down automatically
740 self.think = door_go_down;
741 self.nextthink = self.ltime + self.wait;
744 void() door_hit_bottom =
746 if (self.noise1 != "")
747 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
748 self.state = STATE_BOTTOM;
751 void() door_go_down =
753 if (self.noise2 != "")
754 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
757 self.takedamage = DAMAGE_YES;
758 self.health = self.max_health;
761 self.state = STATE_DOWN;
762 SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
767 if (self.state == STATE_UP)
768 return; // allready going up
770 if (self.state == STATE_TOP)
771 { // reset top wait time
772 self.nextthink = self.ltime + self.wait;
776 if (self.noise2 != "")
777 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
778 self.state = STATE_UP;
779 SUB_CalcMove (self.pos2, self.speed, door_hit_top);
786 =============================================================================
790 =============================================================================
798 if (self.owner != self)
799 objerror ("door_fire: self.owner != self");
801 self.message = ""; // no more message
804 if (self.spawnflags & DOOR_TOGGLE)
806 if (self.state == STATE_UP || self.state == STATE_TOP)
813 } while ( (self != starte) && (self != world) );
819 // trigger all paired doors
825 } while ( (self != starte) && (self != world) );
834 //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
835 self.message = ""; // door message are for touch only
837 self.owner.message = "";
839 self.enemy.message = "";
850 void() door_trigger_touch =
852 if (other.health < 1)
855 if (time < self.attack_finished)
857 self.attack_finished = time + 1;
866 void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) door_damage =
869 self.health = self.health - damage;
870 if (self.health <= 0)
874 self.health = self.max_health;
875 self.takedamage = DAMAGE_NO; // wil be reset upon return
891 if (other.classname != "player")
893 if (self.owner.attack_finished > time)
896 self.owner.attack_finished = time + 2;
898 if (self.owner.message != "")
900 if (other.flags & FL_CLIENT)
901 centerprint (other, self.owner.message);
902 sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
907 =============================================================================
911 =============================================================================
915 entity(vector fmins, vector fmaxs) spawn_field =
917 local entity trigger;
921 trigger.classname = "doortriggerfield";
922 trigger.movetype = MOVETYPE_NONE;
923 trigger.solid = SOLID_TRIGGER;
924 trigger.owner = self;
925 trigger.touch = door_trigger_touch;
929 setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
934 float (entity e1, entity e2) EntitiesTouching =
936 if (e1.mins_x > e2.maxs_x)
938 if (e1.mins_y > e2.maxs_y)
940 if (e1.mins_z > e2.maxs_z)
942 if (e1.maxs_x < e2.mins_x)
944 if (e1.maxs_y < e2.mins_y)
946 if (e1.maxs_z < e2.mins_z)
961 local entity t, starte;
962 local vector cmins, cmaxs;
965 return; // already linked by another door
966 if (self.spawnflags & 4)
968 self.owner = self.enemy = self;
969 return; // don't want to link this door
980 self.owner = starte; // master door
983 starte.health = self.health;
985 starte.targetname = self.targetname;
986 if (self.message != "")
987 starte.message = self.message;
989 t = find(t, classname, self.classname);
992 self.enemy = starte; // make the chain a loop
994 // shootable, or triggered doors just needed the owner/enemy links,
995 // they don't spawn a field
1001 if (self.targetname)
1006 self.owner.trigger_field = spawn_field(cmins, cmaxs);
1011 if (EntitiesTouching(self,t))
1014 objerror ("cross connected doors");
1019 if (t.mins_x < cmins_x)
1021 if (t.mins_y < cmins_y)
1023 if (t.mins_z < cmins_z)
1025 if (t.maxs_x > cmaxs_x)
1027 if (t.maxs_y > cmaxs_y)
1029 if (t.maxs_z > cmaxs_z)
1037 /*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK x x TOGGLE
1038 if two doors touch, they are assumed to be connected and operate as a unit.
1040 TOGGLE causes the door to wait in both the start and end states for a trigger event.
1042 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).
1044 "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
1045 "angle" determines the opening direction
1046 "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
1047 "health" if set, door must be shot open
1048 "speed" movement speed (100 default)
1049 "wait" wait before returning (3 default, -1 = never return)
1050 "lip" lip remaining at end of move (8 default)
1051 "dmg" damage to inflict when blocked (2 default)
1058 FIXME: only one sound set available at the time being
1064 //if (!self.deathtype) // map makers can override this
1065 // self.deathtype = " got in the way";
1068 self.max_health = self.health;
1069 self.solid = SOLID_BSP;
1070 self.movetype = MOVETYPE_PUSH;
1071 setorigin (self, self.origin);
1072 setmodel (self, self.model); // precision set below
1073 self.effects |= EF_LOWPRECISION;
1074 self.classname = "door";
1076 self.blocked = door_blocked;
1077 self.use = door_use;
1079 if(self.targetname == "") {
1080 self.spawnflags = 0;
1084 if(self.spawnflags & 4)
1087 if(self.dmg & (!self.message))
1088 self.message = "was in the wrong place.";
1092 if (self.sounds > 0)
1094 precache_sound ("plats/medplat1.wav");
1095 precache_sound ("plats/medplat2.wav");
1096 self.noise2 = "plats/medplat1.wav";
1097 self.noise1 = "plats/medplat2.wav";
1109 self.pos1 = self.origin;
1110 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
1112 // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
1113 // but spawn in the open position
1114 if (self.spawnflags & DOOR_START_OPEN)
1116 setorigin (self, self.pos2);
1117 self.pos2 = self.pos1;
1118 self.pos1 = self.origin;
1121 self.state = STATE_BOTTOM;
1125 self.takedamage = DAMAGE_YES;
1126 self.event_damage = door_damage;
1132 self.touch = door_touch;
1134 // LinkDoors can't be done until all of the doors have been spawned, so
1135 // the sizes can be detected properly.
1136 self.think = LinkDoors;
1137 self.nextthink = self.ltime + 0.1;
1141 =============================================================================
1145 =============================================================================
1148 void() fd_secret_move1;
1149 void() fd_secret_move2;
1150 void() fd_secret_move3;
1151 void() fd_secret_move4;
1152 void() fd_secret_move5;
1153 void() fd_secret_move6;
1154 void() fd_secret_done;
1156 float SECRET_OPEN_ONCE = 1; // stays open
1157 float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
1158 float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
1159 float SECRET_NO_SHOOT = 8; // only opened by trigger
1160 float SECRET_YES_SHOOT = 16; // shootable even if targeted
1163 void () fd_secret_use =
1167 self.health = 10000;
1168 self.bot_attack = TRUE;
1170 // exit if still moving around...
1171 if (self.origin != self.oldorigin)
1174 self.message = ""; // no more message
1176 SUB_UseTargets(); // fire all targets / killtargets
1178 self.velocity = '0 0 0';
1180 // Make a sound, wait a little...
1182 if (self.noise1 != "")
1183 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
1184 self.nextthink = self.ltime + 0.1;
1186 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
1187 makevectors(self.mangle);
1191 if (self.spawnflags & SECRET_1ST_DOWN)
1192 self.t_width = fabs(v_up * self.size);
1194 self.t_width = fabs(v_right * self.size);
1198 self.t_length = fabs(v_forward * self.size);
1200 if (self.spawnflags & SECRET_1ST_DOWN)
1201 self.dest1 = self.origin - v_up * self.t_width;
1203 self.dest1 = self.origin + v_right * (self.t_width * temp);
1205 self.dest2 = self.dest1 + v_forward * self.t_length;
1206 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
1207 if (self.noise2 != "")
1208 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1211 // Wait after first movement...
1212 void () fd_secret_move1 =
1214 self.nextthink = self.ltime + 1.0;
1215 self.think = fd_secret_move2;
1216 if (self.noise3 != "")
1217 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1220 // Start moving sideways w/sound...
1221 void () fd_secret_move2 =
1223 if (self.noise2 != "")
1224 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1225 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
1228 // Wait here until time to go back...
1229 void () fd_secret_move3 =
1231 if (self.noise3 != "")
1232 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1233 if (!(self.spawnflags & SECRET_OPEN_ONCE))
1235 self.nextthink = self.ltime + self.wait;
1236 self.think = fd_secret_move4;
1241 void () fd_secret_move4 =
1243 if (self.noise2 != "")
1244 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1245 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
1249 void () fd_secret_move5 =
1251 self.nextthink = self.ltime + 1.0;
1252 self.think = fd_secret_move6;
1253 if (self.noise3 != "")
1254 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1257 void () fd_secret_move6 =
1259 if (self.noise2 != "")
1260 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1261 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
1264 void () fd_secret_done =
1266 if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
1268 self.health = 10000;
1269 self.takedamage = DAMAGE_YES;
1270 //self.th_pain = fd_secret_use;
1272 if (self.noise3 != "")
1273 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1276 void () secret_blocked =
1278 if (time < self.attack_finished)
1280 self.attack_finished = time + 0.5;
1281 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
1291 void() secret_touch =
1293 if (activator.classname != "player")
1295 if (self.attack_finished > time)
1298 self.attack_finished = time + 2;
1302 if (other.flags & FL_CLIENT)
1303 centerprint (other, self.message);
1304 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
1309 /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
1310 Basic secret door. Slides back, then to the side. Angle determines direction.
1311 wait = # of seconds before coming back
1312 1st_left = 1st move is left of arrow
1313 1st_down = 1st move is down from arrow
1314 always_shoot = even if targeted, keep shootable
1315 t_width = override WIDTH to move back (or height if going down)
1316 t_length = override LENGTH to move sideways
1317 "dmg" damage to inflict when blocked (2 default)
1319 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
1326 void () func_door_secret =
1328 /*if (!self.deathtype) // map makers can override this
1329 self.deathtype = " got in the way";*/
1335 self.mangle = self.angles;
1336 self.angles = '0 0 0';
1337 self.solid = SOLID_BSP;
1338 self.movetype = MOVETYPE_PUSH;
1339 self.classname = "door";
1340 setmodel (self, self.model); // precision set below
1341 self.effects |= EF_LOWPRECISION;
1342 setorigin (self, self.origin);
1344 self.touch = secret_touch;
1345 self.blocked = secret_blocked;
1347 self.use = fd_secret_use;
1348 if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
1350 self.health = 10000;
1351 self.takedamage = DAMAGE_YES;
1352 self.event_damage = fd_secret_use;
1354 self.oldorigin = self.origin;
1356 self.wait = 5; // 5 seconds before closing