doors.qc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. /* Copyright (C) 1996-2022 id Software LLC
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. // updated to quake 1.06 - 10/8/96
  16. float DOOR_START_OPEN = 1;
  17. float DOOR_DONT_LINK = 4;
  18. float DOOR_GOLD_KEY = 8;
  19. float DOOR_SILVER_KEY = 16;
  20. float DOOR_TOGGLE = 32;
  21. /*
  22. Doors are similar to buttons, but can spawn a fat trigger field around them
  23. to open without a touch, and they link together to form simultanious
  24. double/quad doors.
  25. Door.owner is the master door. If there is only one door, it points to itself.
  26. If multiple doors, all will point to a single one.
  27. Door.enemy chains from the master door through all doors linked in the chain.
  28. */
  29. /*
  30. =============================================================================
  31. THINK FUNCTIONS
  32. =============================================================================
  33. */
  34. void() door_go_down;
  35. void() door_go_up;
  36. void() door_blocked =
  37. {
  38. T_Damage (other, self, self, self.dmg);
  39. // if a door has a negative wait, it would never come back if blocked,
  40. // so let it just squash the object to death real fast
  41. if (self.wait >= 0)
  42. {
  43. if (self.state == STATE_DOWN)
  44. door_go_up ();
  45. else
  46. door_go_down ();
  47. }
  48. };
  49. void() door_hit_top =
  50. {
  51. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  52. self.state = STATE_TOP;
  53. if (self.spawnflags & DOOR_TOGGLE)
  54. return; // don't come down automatically
  55. self.think = door_go_down;
  56. self.nextthink = self.ltime + self.wait;
  57. };
  58. void() door_hit_bottom =
  59. {
  60. sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  61. self.state = STATE_BOTTOM;
  62. };
  63. void() door_go_down =
  64. {
  65. sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  66. if (self.max_health)
  67. {
  68. self.takedamage = DAMAGE_YES;
  69. self.health = self.max_health;
  70. }
  71. self.state = STATE_DOWN;
  72. SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
  73. };
  74. void() door_go_up =
  75. {
  76. if (self.state == STATE_UP)
  77. return; // allready going up
  78. if (self.state == STATE_TOP)
  79. { // reset top wait time
  80. self.nextthink = self.ltime + self.wait;
  81. return;
  82. }
  83. sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  84. self.state = STATE_UP;
  85. SUB_CalcMove (self.pos2, self.speed, door_hit_top);
  86. SUB_UseTargets();
  87. };
  88. /*
  89. =============================================================================
  90. ACTIVATION FUNCTIONS
  91. =============================================================================
  92. */
  93. void() door_fire =
  94. {
  95. local entity oself;
  96. local entity starte;
  97. if (self.owner != self)
  98. objerror ("door_fire: self.owner != self");
  99. // play use key sound
  100. if (self.items)
  101. sound (self, CHAN_VOICE, self.noise4, 1, ATTN_NORM);
  102. self.message = string_null; // no more message
  103. oself = self;
  104. if (self.spawnflags & DOOR_TOGGLE)
  105. {
  106. if (self.state == STATE_UP || self.state == STATE_TOP)
  107. {
  108. starte = self;
  109. do
  110. {
  111. door_go_down ();
  112. self = self.enemy;
  113. } while ( (self != starte) && (self != world) );
  114. self = oself;
  115. return;
  116. }
  117. }
  118. // trigger all paired doors
  119. starte = self;
  120. do
  121. {
  122. door_go_up ();
  123. self = self.enemy;
  124. } while ( (self != starte) && (self != world) );
  125. self = oself;
  126. };
  127. void() door_use =
  128. {
  129. local entity oself;
  130. self.message = ""; // door message are for touch only
  131. self.owner.message = "";
  132. self.enemy.message = "";
  133. oself = self;
  134. self = self.owner;
  135. door_fire ();
  136. self = oself;
  137. };
  138. void() door_trigger_touch =
  139. {
  140. if (other.health <= 0)
  141. return;
  142. if (time < self.attack_finished)
  143. return;
  144. self.attack_finished = time + 1;
  145. activator = other;
  146. self = self.owner;
  147. door_use ();
  148. };
  149. void() door_killed =
  150. {
  151. local entity oself;
  152. oself = self;
  153. self = self.owner;
  154. self.health = self.max_health;
  155. self.takedamage = DAMAGE_NO; // wil be reset upon return
  156. door_use ();
  157. self = oself;
  158. };
  159. /*
  160. ================
  161. door_touch
  162. Prints messages and opens key doors
  163. ================
  164. */
  165. void() door_touch =
  166. {
  167. if (other.classname != "player")
  168. return;
  169. if (self.owner.attack_finished > time)
  170. return;
  171. self.owner.attack_finished = time + 2;
  172. if (self.owner.message != "")
  173. {
  174. centerprint (other, self.owner.message);
  175. sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
  176. }
  177. // key door stuff
  178. if (!self.items)
  179. return;
  180. // FIXME: blink key on player's status bar
  181. if ( (self.items & other.items) != self.items )
  182. {
  183. if (self.owner.items == IT_KEY1)
  184. {
  185. if (world.worldtype == 2)
  186. {
  187. centerprint (other, "$qc_need_silver_keycard");
  188. sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  189. }
  190. else if (world.worldtype == 1)
  191. {
  192. centerprint (other, "$qc_need_silver_runekey");
  193. sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  194. }
  195. else if (world.worldtype == 0)
  196. {
  197. centerprint (other, "$qc_need_silver_key");
  198. sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  199. }
  200. }
  201. else
  202. {
  203. if (world.worldtype == 2)
  204. {
  205. centerprint (other, "$qc_need_gold_keycard");
  206. sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  207. }
  208. else if (world.worldtype == 1)
  209. {
  210. centerprint (other, "$qc_need_gold_runekey");
  211. sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  212. }
  213. else if (world.worldtype == 0)
  214. {
  215. centerprint (other, "$qc_need_gold_key");
  216. sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  217. }
  218. }
  219. return;
  220. }
  221. other.items = other.items - self.items;
  222. self.touch = SUB_Null;
  223. if (self.enemy)
  224. self.enemy.touch = SUB_Null; // get paired door
  225. door_use ();
  226. };
  227. /*
  228. =============================================================================
  229. SPAWNING FUNCTIONS
  230. =============================================================================
  231. */
  232. entity(vector fmins, vector fmaxs) spawn_field =
  233. {
  234. local entity trigger;
  235. local vector t1, t2;
  236. trigger = spawn();
  237. trigger.movetype = MOVETYPE_NONE;
  238. trigger.solid = SOLID_TRIGGER;
  239. trigger.owner = self;
  240. trigger.touch = door_trigger_touch;
  241. t1 = fmins;
  242. t2 = fmaxs;
  243. setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
  244. return (trigger);
  245. };
  246. float (entity e1, entity e2) EntitiesTouching =
  247. {
  248. if (e1.mins_x > e2.maxs_x)
  249. return FALSE;
  250. if (e1.mins_y > e2.maxs_y)
  251. return FALSE;
  252. if (e1.mins_z > e2.maxs_z)
  253. return FALSE;
  254. if (e1.maxs_x < e2.mins_x)
  255. return FALSE;
  256. if (e1.maxs_y < e2.mins_y)
  257. return FALSE;
  258. if (e1.maxs_z < e2.mins_z)
  259. return FALSE;
  260. return TRUE;
  261. };
  262. /*
  263. =============
  264. LinkDoors
  265. =============
  266. */
  267. void() LinkDoors =
  268. {
  269. local entity t, starte;
  270. local vector cmins, cmaxs;
  271. if (self.enemy)
  272. return; // already linked by another door
  273. if (self.spawnflags & 4)
  274. {
  275. self.owner = self.enemy = self;
  276. return; // don't want to link this door
  277. }
  278. cmins = self.mins;
  279. cmaxs = self.maxs;
  280. starte = self;
  281. t = self;
  282. do
  283. {
  284. self.owner = starte; // master door
  285. if (self.health)
  286. starte.health = self.health;
  287. if (self.targetname)
  288. starte.targetname = self.targetname;
  289. if (self.message != "")
  290. starte.message = self.message;
  291. t = find (t, classname, self.classname);
  292. if (!t)
  293. {
  294. self.enemy = starte; // make the chain a loop
  295. // shootable, fired, or key doors just needed the owner/enemy links,
  296. // they don't spawn a field
  297. self = self.owner;
  298. if (self.health)
  299. return;
  300. if (self.targetname)
  301. return;
  302. if (self.items)
  303. return;
  304. self.owner.trigger_field = spawn_field(cmins, cmaxs);
  305. return;
  306. }
  307. if (EntitiesTouching(self,t))
  308. {
  309. if (t.enemy)
  310. objerror ("cross connected doors");
  311. self.enemy = t;
  312. self = t;
  313. if (t.mins_x < cmins_x)
  314. cmins_x = t.mins_x;
  315. if (t.mins_y < cmins_y)
  316. cmins_y = t.mins_y;
  317. if (t.mins_z < cmins_z)
  318. cmins_z = t.mins_z;
  319. if (t.maxs_x > cmaxs_x)
  320. cmaxs_x = t.maxs_x;
  321. if (t.maxs_y > cmaxs_y)
  322. cmaxs_y = t.maxs_y;
  323. if (t.maxs_z > cmaxs_z)
  324. cmaxs_z = t.maxs_z;
  325. }
  326. } while (1 );
  327. };
  328. /*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
  329. if two doors touch, they are assumed to be connected and operate as a unit.
  330. TOGGLE causes the door to wait in both the start and end states for a trigger event.
  331. 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).
  332. Key doors are allways wait -1.
  333. "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
  334. "angle" determines the opening direction
  335. "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
  336. "health" if set, door must be shot open
  337. "speed" movement speed (100 default)
  338. "wait" wait before returning (3 default, -1 = never return)
  339. "lip" lip remaining at end of move (8 default)
  340. "dmg" damage to inflict when blocked (2 default)
  341. "sounds"
  342. 0) no sound
  343. 1) stone
  344. 2) base
  345. 3) stone chain
  346. 4) screechy metal
  347. */
  348. void() func_door =
  349. {
  350. local vector tempVect;
  351. if (world.worldtype == 0)
  352. {
  353. precache_sound ("doors/medtry.wav");
  354. precache_sound ("doors/meduse.wav");
  355. self.noise3 = "doors/medtry.wav";
  356. self.noise4 = "doors/meduse.wav";
  357. }
  358. else if (world.worldtype == 1)
  359. {
  360. precache_sound ("doors/runetry.wav");
  361. precache_sound ("doors/runeuse.wav");
  362. self.noise3 = "doors/runetry.wav";
  363. self.noise4 = "doors/runeuse.wav";
  364. }
  365. else if (world.worldtype == 2)
  366. {
  367. precache_sound ("doors/basetry.wav");
  368. precache_sound ("doors/baseuse.wav");
  369. self.noise3 = "doors/basetry.wav";
  370. self.noise4 = "doors/baseuse.wav";
  371. }
  372. else
  373. {
  374. dprint ("no worldtype set!\n");
  375. }
  376. if (self.sounds == 0)
  377. {
  378. precache_sound ("misc/null.wav");
  379. precache_sound ("misc/null.wav");
  380. self.noise1 = "misc/null.wav";
  381. self.noise2 = "misc/null.wav";
  382. }
  383. if (self.sounds == 1)
  384. {
  385. precache_sound ("doors/drclos4.wav");
  386. precache_sound ("doors/doormv1.wav");
  387. self.noise1 = "doors/drclos4.wav";
  388. self.noise2 = "doors/doormv1.wav";
  389. }
  390. if (self.sounds == 2)
  391. {
  392. precache_sound ("doors/hydro1.wav");
  393. precache_sound ("doors/hydro2.wav");
  394. self.noise2 = "doors/hydro1.wav";
  395. self.noise1 = "doors/hydro2.wav";
  396. }
  397. if (self.sounds == 3)
  398. {
  399. precache_sound ("doors/stndr1.wav");
  400. precache_sound ("doors/stndr2.wav");
  401. self.noise2 = "doors/stndr1.wav";
  402. self.noise1 = "doors/stndr2.wav";
  403. }
  404. if (self.sounds == 4)
  405. {
  406. precache_sound ("doors/ddoor1.wav");
  407. precache_sound ("doors/ddoor2.wav");
  408. self.noise1 = "doors/ddoor2.wav";
  409. self.noise2 = "doors/ddoor1.wav";
  410. }
  411. SetMovedir ();
  412. self.max_health = self.health;
  413. self.solid = SOLID_BSP;
  414. self.movetype = MOVETYPE_PUSH;
  415. setorigin (self, self.origin);
  416. setmodel (self, self.model);
  417. self.classname = "door";
  418. self.blocked = door_blocked;
  419. self.use = door_use;
  420. if (self.spawnflags & DOOR_SILVER_KEY)
  421. self.items = IT_KEY1;
  422. if (self.spawnflags & DOOR_GOLD_KEY)
  423. self.items = IT_KEY2;
  424. if (!self.speed)
  425. self.speed = 100;
  426. if (!self.wait)
  427. self.wait = 3;
  428. if (!self.lip)
  429. self.lip = 8;
  430. if (!self.dmg)
  431. self.dmg = 2;
  432. self.pos1=self.origin;
  433. // self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
  434. // PGM fix for cameron's door problem - 02/19/97
  435. tempVect = self.movedir;
  436. if (tempVect_x < 0)
  437. tempVect_x = 0 - tempVect_x;
  438. if (tempVect_y < 0)
  439. tempVect_y = 0 - tempVect_y;
  440. // if (tempVect_z < 0)
  441. // tempVect_z = 0 - tempVect_z;
  442. // self.pos2 = self.pos1 + self.movedir*(tempVect*self.size - self.lip);
  443. vector movedir_fabs = { fabs(self.movedir[0]), fabs(self.movedir[1]), fabs(self.movedir[2]) };
  444. self.pos2 = self.pos1 + ((movedir_fabs * self.size) - self.lip) * self.movedir;
  445. // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
  446. // but spawn in the open position
  447. if (self.spawnflags & DOOR_START_OPEN)
  448. {
  449. setorigin (self, self.pos2);
  450. self.pos2 = self.pos1;
  451. self.pos1 = self.origin;
  452. }
  453. self.state = STATE_BOTTOM;
  454. if (self.health)
  455. {
  456. self.takedamage = DAMAGE_YES;
  457. self.th_die = door_killed;
  458. }
  459. if (self.items)
  460. self.wait = -1;
  461. self.touch = door_touch;
  462. // LinkDoors can't be done until all of the doors have been spawned, so
  463. // the sizes can be detected properly.
  464. self.think = LinkDoors;
  465. self.nextthink = self.ltime + 0.1;
  466. };
  467. /*
  468. =============================================================================
  469. SECRET DOORS
  470. =============================================================================
  471. */
  472. void() fd_secret_move1;
  473. void() fd_secret_move2;
  474. void() fd_secret_move3;
  475. void() fd_secret_move4;
  476. void() fd_secret_move5;
  477. void() fd_secret_move6;
  478. void() fd_secret_done;
  479. float SECRET_OPEN_ONCE = 1; // stays open
  480. float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
  481. float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
  482. float SECRET_NO_SHOOT = 8; // only opened by trigger
  483. float SECRET_YES_SHOOT = 16; // shootable even if targeted
  484. void () fd_secret_use =
  485. {
  486. local float temp;
  487. self.health = 10000;
  488. // exit if still moving around...
  489. if (self.origin != self.oldorigin)
  490. return;
  491. self.message = string_null; // no more message
  492. SUB_UseTargets(); // fire all targets / killtargets
  493. if (!(self.spawnflags & SECRET_NO_SHOOT))
  494. {
  495. self.th_pain = SUB_Null;
  496. self.takedamage = DAMAGE_NO;
  497. }
  498. self.velocity = '0 0 0';
  499. // Make a sound, wait a little...
  500. sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  501. self.nextthink = self.ltime + 0.1;
  502. temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
  503. makevectors(self.mangle);
  504. if (!self.t_width)
  505. {
  506. if (self.spawnflags & SECRET_1ST_DOWN)
  507. self. t_width = fabs(v_up * self.size);
  508. else
  509. self. t_width = fabs(v_right * self.size);
  510. }
  511. if (!self.t_length)
  512. self. t_length = fabs(v_forward * self.size);
  513. if (self.spawnflags & SECRET_1ST_DOWN)
  514. self.dest1 = self.origin - v_up * self.t_width;
  515. else
  516. self.dest1 = self.origin + v_right * (self.t_width * temp);
  517. self.dest2 = self.dest1 + v_forward * self.t_length;
  518. SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
  519. sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  520. };
  521. // Wait after first movement...
  522. void () fd_secret_move1 =
  523. {
  524. self.nextthink = self.ltime + 1.0;
  525. self.think = fd_secret_move2;
  526. sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  527. };
  528. // Start moving sideways w/sound...
  529. void () fd_secret_move2 =
  530. {
  531. sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  532. SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
  533. };
  534. // Wait here until time to go back...
  535. void () fd_secret_move3 =
  536. {
  537. sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  538. if (!(self.spawnflags & SECRET_OPEN_ONCE))
  539. {
  540. self.nextthink = self.ltime + self.wait;
  541. self.think = fd_secret_move4;
  542. }
  543. };
  544. // Move backward...
  545. void () fd_secret_move4 =
  546. {
  547. sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  548. SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
  549. };
  550. // Wait 1 second...
  551. void () fd_secret_move5 =
  552. {
  553. self.nextthink = self.ltime + 1.0;
  554. self.think = fd_secret_move6;
  555. sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  556. };
  557. void () fd_secret_move6 =
  558. {
  559. sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  560. SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
  561. };
  562. void () fd_secret_done =
  563. {
  564. if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
  565. {
  566. self.health = 10000;
  567. self.takedamage = DAMAGE_YES;
  568. self.th_pain = fd_secret_use;
  569. }
  570. sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  571. };
  572. void () secret_blocked =
  573. {
  574. if (time < self.attack_finished)
  575. return;
  576. self.attack_finished = time + 0.5;
  577. T_Damage (other, self, self, self.dmg);
  578. };
  579. /*
  580. ================
  581. secret_touch
  582. Prints messages
  583. ================
  584. */
  585. void() secret_touch =
  586. {
  587. if (other.classname != "player")
  588. return;
  589. if (self.attack_finished > time)
  590. return;
  591. self.attack_finished = time + 2;
  592. if (self.message)
  593. {
  594. centerprint (other, self.message);
  595. sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
  596. }
  597. };
  598. /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
  599. Basic secret door. Slides back, then to the side. Angle determines direction.
  600. wait = # of seconds before coming back
  601. 1st_left = 1st move is left of arrow
  602. 1st_down = 1st move is down from arrow
  603. always_shoot = even if targeted, keep shootable
  604. t_width = override WIDTH to move back (or height if going down)
  605. t_length = override LENGTH to move sideways
  606. "dmg" damage to inflict when blocked (2 default)
  607. If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
  608. "sounds"
  609. 1) medieval
  610. 2) metal
  611. 3) base
  612. */
  613. void () func_door_secret =
  614. {
  615. if (self.sounds == 0)
  616. self.sounds = 3;
  617. if (self.sounds == 1)
  618. {
  619. precache_sound ("doors/latch2.wav");
  620. precache_sound ("doors/winch2.wav");
  621. precache_sound ("doors/drclos4.wav");
  622. self.noise1 = "doors/latch2.wav";
  623. self.noise2 = "doors/winch2.wav";
  624. self.noise3 = "doors/drclos4.wav";
  625. }
  626. if (self.sounds == 2)
  627. {
  628. precache_sound ("doors/airdoor1.wav");
  629. precache_sound ("doors/airdoor2.wav");
  630. self.noise2 = "doors/airdoor1.wav";
  631. self.noise1 = "doors/airdoor2.wav";
  632. self.noise3 = "doors/airdoor2.wav";
  633. }
  634. if (self.sounds == 3)
  635. {
  636. precache_sound ("doors/basesec1.wav");
  637. precache_sound ("doors/basesec2.wav");
  638. self.noise2 = "doors/basesec1.wav";
  639. self.noise1 = "doors/basesec2.wav";
  640. self.noise3 = "doors/basesec2.wav";
  641. }
  642. if (!self.dmg)
  643. self.dmg = 2;
  644. // Magic formula...
  645. self.mangle = self.angles;
  646. self.angles = '0 0 0';
  647. self.solid = SOLID_BSP;
  648. self.movetype = MOVETYPE_PUSH;
  649. self.classname = "door";
  650. setmodel (self, self.model);
  651. setorigin (self, self.origin);
  652. self.touch = secret_touch;
  653. self.blocked = secret_blocked;
  654. self.speed = 50;
  655. self.use = fd_secret_use;
  656. if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
  657. {
  658. self.health = 10000;
  659. self.takedamage = DAMAGE_YES;
  660. self.th_pain = fd_secret_use;
  661. self.th_die = fd_secret_use;
  662. }
  663. self.oldorigin = self.origin;
  664. if (!self.wait)
  665. self.wait = 5; // 5 seconds before closing
  666. };