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!!
694 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
697 if((self.dmg) && (other.takedamage == DAMAGE_YES)) // Shall we bite?
698 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
700 //Dont chamge direction for dead or dying stuff
701 if(other.deadflag != DEAD_NO && (other.takedamage == DAMAGE_NO)) {
704 if (self.state == STATE_DOWN)
710 //gib dying stuff just to make sure
711 if((self.dmg) && (other.takedamage != DAMAGE_NO)) // Shall we bite?
712 Damage (other, self, self, 10000, DEATH_HURTTRIGGER, other.origin, '0 0 0');
716 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
717 // if a door has a negative wait, it would never come back if blocked,
718 // so let it just squash the object to death real fast
719 /* if (self.wait >= 0)
721 if (self.state == STATE_DOWN)
730 void() door_hit_top =
732 if (self.noise1 != "")
733 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
734 self.state = STATE_TOP;
735 if (self.spawnflags & DOOR_TOGGLE)
736 return; // don't come down automatically
737 self.think = door_go_down;
738 self.nextthink = self.ltime + self.wait;
741 void() door_hit_bottom =
743 if (self.noise1 != "")
744 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
745 self.state = STATE_BOTTOM;
748 void() door_go_down =
750 if (self.noise2 != "")
751 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
754 self.takedamage = DAMAGE_YES;
755 self.health = self.max_health;
758 self.state = STATE_DOWN;
759 SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
764 if (self.state == STATE_UP)
765 return; // allready going up
767 if (self.state == STATE_TOP)
768 { // reset top wait time
769 self.nextthink = self.ltime + self.wait;
773 if (self.noise2 != "")
774 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
775 self.state = STATE_UP;
776 SUB_CalcMove (self.pos2, self.speed, door_hit_top);
783 =============================================================================
787 =============================================================================
795 if (self.owner != self)
796 objerror ("door_fire: self.owner != self");
798 self.message = ""; // no more message
801 if (self.spawnflags & DOOR_TOGGLE)
803 if (self.state == STATE_UP || self.state == STATE_TOP)
810 } while ( (self != starte) && (self != world) );
816 // trigger all paired doors
822 } while ( (self != starte) && (self != world) );
831 //dprint("door_use (model: ");dprint(self.model);dprint(")\n");
832 self.message = ""; // door message are for touch only
834 self.owner.message = "";
836 self.enemy.message = "";
847 void() door_trigger_touch =
849 if (other.health < 1)
852 if (time < self.attack_finished)
854 self.attack_finished = time + 1;
863 void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) door_damage =
866 self.health = self.health - damage;
867 if (self.health <= 0)
871 self.health = self.max_health;
872 self.takedamage = DAMAGE_NO; // wil be reset upon return
888 if (other.classname != "player")
890 if (self.owner.attack_finished > time)
893 self.owner.attack_finished = time + 2;
895 if (self.owner.message != "")
897 if (other.flags & FL_CLIENT)
898 centermsg_setfor (other, CENTERMSG_TRIGGER, self.owner.message);
899 sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
904 =============================================================================
908 =============================================================================
912 entity(vector fmins, vector fmaxs) spawn_field =
914 local entity trigger;
918 trigger.classname = "doortriggerfield";
919 trigger.movetype = MOVETYPE_NONE;
920 trigger.solid = SOLID_TRIGGER;
921 trigger.owner = self;
922 trigger.touch = door_trigger_touch;
926 setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
931 float (entity e1, entity e2) EntitiesTouching =
933 if (e1.mins_x > e2.maxs_x)
935 if (e1.mins_y > e2.maxs_y)
937 if (e1.mins_z > e2.maxs_z)
939 if (e1.maxs_x < e2.mins_x)
941 if (e1.maxs_y < e2.mins_y)
943 if (e1.maxs_z < e2.mins_z)
958 local entity t, starte;
959 local vector cmins, cmaxs;
962 return; // already linked by another door
963 if (self.spawnflags & 4)
965 self.owner = self.enemy = self;
966 return; // don't want to link this door
977 self.owner = starte; // master door
980 starte.health = self.health;
982 starte.targetname = self.targetname;
983 if (self.message != "")
984 starte.message = self.message;
986 t = find(t, classname, self.classname);
989 self.enemy = starte; // make the chain a loop
991 // shootable, or triggered doors just needed the owner/enemy links,
992 // they don't spawn a field
1003 self.owner.trigger_field = spawn_field(cmins, cmaxs);
1008 if (EntitiesTouching(self,t))
1011 objerror ("cross connected doors");
1016 if (t.mins_x < cmins_x)
1018 if (t.mins_y < cmins_y)
1020 if (t.mins_z < cmins_z)
1022 if (t.maxs_x > cmaxs_x)
1024 if (t.maxs_y > cmaxs_y)
1026 if (t.maxs_z > cmaxs_z)
1034 /*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK x x TOGGLE
1035 if two doors touch, they are assumed to be connected and operate as a unit.
1037 TOGGLE causes the door to wait in both the start and end states for a trigger event.
1039 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).
1041 "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
1042 "angle" determines the opening direction
1043 "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
1044 "health" if set, door must be shot open
1045 "speed" movement speed (100 default)
1046 "wait" wait before returning (3 default, -1 = never return)
1047 "lip" lip remaining at end of move (8 default)
1048 "dmg" damage to inflict when blocked (2 default)
1055 FIXME: only one sound set available at the time being
1061 //if (!self.deathtype) // map makers can override this
1062 // self.deathtype = " got in the way";
1065 self.max_health = self.health;
1066 self.solid = SOLID_BSP;
1067 self.movetype = MOVETYPE_PUSH;
1068 setorigin (self, self.origin);
1069 setmodel (self, self.model);
1070 self.classname = "door";
1072 self.blocked = door_blocked;
1073 self.use = door_use;
1075 if(self.targetname == "") {
1076 self.spawnflags = 0;
1080 if(self.spawnflags == 4)
1083 if(self.dmg & (!self.message))
1084 self.message = "was in the wrong place.";
1088 if (self.sounds > 0)
1090 precache_sound ("plats/medplat1.wav");
1091 precache_sound ("plats/medplat2.wav");
1092 self.noise2 = "plats/medplat1.wav";
1093 self.noise1 = "plats/medplat2.wav";
1105 self.pos1 = self.origin;
1106 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
1108 // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
1109 // but spawn in the open position
1110 if (self.spawnflags & DOOR_START_OPEN)
1112 setorigin (self, self.pos2);
1113 self.pos2 = self.pos1;
1114 self.pos1 = self.origin;
1117 self.state = STATE_BOTTOM;
1121 self.takedamage = DAMAGE_YES;
1122 self.event_damage = door_damage;
1128 self.touch = door_touch;
1130 // LinkDoors can't be done until all of the doors have been spawned, so
1131 // the sizes can be detected properly.
1132 self.think = LinkDoors;
1133 self.nextthink = self.ltime + 0.1;
1137 =============================================================================
1141 =============================================================================
1144 void() fd_secret_move1;
1145 void() fd_secret_move2;
1146 void() fd_secret_move3;
1147 void() fd_secret_move4;
1148 void() fd_secret_move5;
1149 void() fd_secret_move6;
1150 void() fd_secret_done;
1152 float SECRET_OPEN_ONCE = 1; // stays open
1153 float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
1154 float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
1155 float SECRET_NO_SHOOT = 8; // only opened by trigger
1156 float SECRET_YES_SHOOT = 16; // shootable even if targeted
1159 void () fd_secret_use =
1163 self.health = 10000;
1164 self.bot_attack = TRUE;
1166 // exit if still moving around...
1167 if (self.origin != self.oldorigin)
1170 self.message = ""; // no more message
1172 SUB_UseTargets(); // fire all targets / killtargets
1174 self.velocity = '0 0 0';
1176 // Make a sound, wait a little...
1178 if (self.noise1 != "")
1179 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
1180 self.nextthink = self.ltime + 0.1;
1182 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
1183 makevectors(self.mangle);
1187 if (self.spawnflags & SECRET_1ST_DOWN)
1188 self.t_width = fabs(v_up * self.size);
1190 self.t_width = fabs(v_right * self.size);
1194 self.t_length = fabs(v_forward * self.size);
1196 if (self.spawnflags & SECRET_1ST_DOWN)
1197 self.dest1 = self.origin - v_up * self.t_width;
1199 self.dest1 = self.origin + v_right * (self.t_width * temp);
1201 self.dest2 = self.dest1 + v_forward * self.t_length;
1202 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
1203 if (self.noise2 != "")
1204 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1207 // Wait after first movement...
1208 void () fd_secret_move1 =
1210 self.nextthink = self.ltime + 1.0;
1211 self.think = fd_secret_move2;
1212 if (self.noise3 != "")
1213 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1216 // Start moving sideways w/sound...
1217 void () fd_secret_move2 =
1219 if (self.noise2 != "")
1220 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1221 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
1224 // Wait here until time to go back...
1225 void () fd_secret_move3 =
1227 if (self.noise3 != "")
1228 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1229 if (!(self.spawnflags & SECRET_OPEN_ONCE))
1231 self.nextthink = self.ltime + self.wait;
1232 self.think = fd_secret_move4;
1237 void () fd_secret_move4 =
1239 if (self.noise2 != "")
1240 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1241 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
1245 void () fd_secret_move5 =
1247 self.nextthink = self.ltime + 1.0;
1248 self.think = fd_secret_move6;
1249 if (self.noise3 != "")
1250 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1253 void () fd_secret_move6 =
1255 if (self.noise2 != "")
1256 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
1257 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
1260 void () fd_secret_done =
1262 if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
1264 self.health = 10000;
1265 self.takedamage = DAMAGE_YES;
1266 //self.th_pain = fd_secret_use;
1268 if (self.noise3 != "")
1269 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
1272 void () secret_blocked =
1274 if (time < self.attack_finished)
1276 self.attack_finished = time + 0.5;
1277 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
1287 void() secret_touch =
1289 if (activator.classname != "player")
1291 if (self.attack_finished > time)
1294 self.attack_finished = time + 2;
1298 if (other.flags & FL_CLIENT)
1299 centermsg_setfor (other, CENTERMSG_TRIGGER, self.message);
1300 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
1305 /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
1306 Basic secret door. Slides back, then to the side. Angle determines direction.
1307 wait = # of seconds before coming back
1308 1st_left = 1st move is left of arrow
1309 1st_down = 1st move is down from arrow
1310 always_shoot = even if targeted, keep shootable
1311 t_width = override WIDTH to move back (or height if going down)
1312 t_length = override LENGTH to move sideways
1313 "dmg" damage to inflict when blocked (2 default)
1315 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
1322 void () func_door_secret =
1324 /*if (!self.deathtype) // map makers can override this
1325 self.deathtype = " got in the way";*/
1331 self.mangle = self.angles;
1332 self.angles = '0 0 0';
1333 self.solid = SOLID_BSP;
1334 self.movetype = MOVETYPE_PUSH;
1335 self.classname = "door";
1336 setmodel (self, self.model);
1337 setorigin (self, self.origin);
1339 self.touch = secret_touch;
1340 self.blocked = secret_blocked;
1342 self.use = fd_secret_use;
1343 if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
1345 self.health = 10000;
1346 self.takedamage = DAMAGE_YES;
1347 self.event_damage = fd_secret_use;
1349 self.oldorigin = self.origin;
1351 self.wait = 5; // 5 seconds before closing