1 2float DOOR_START_OPEN = 1; 3float DOOR_DONT_LINK = 4; 4float DOOR_GOLD_KEY = 8; 5float DOOR_SILVER_KEY = 16; 6float DOOR_TOGGLE = 32; 7 8/* 9 10Doors are similar to buttons, but can spawn a fat trigger field around them 11to open without a touch, and they link together to form simultanious 12double/quad doors. 13 14Door.owner is the master door. If there is only one door, it points to itself. 15If multiple doors, all will point to a single one. 16 17Door.enemy chains from the master door through all doors linked in the chain. 18 19*/ 20 21/* 22============================================================================= 23 24THINK FUNCTIONS 25 26============================================================================= 27*/ 28 29void() door_go_down; 30void() door_go_up; 31 32void() door_blocked = 33{ 34 T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic); 35 36// if a door has a negative wait, it would never come back if blocked, 37// so let it just squash the object to death real fast 38 if (!other.iscorpse) // crush dead bodies 39 if (self.wait >= 0) 40 { 41 if (self.state == STATE_DOWN) 42 door_go_up (); 43 else 44 door_go_down (); 45 } 46}; 47 48 49void() door_hit_top = 50{ 51 if (self.noise1 != "") 52 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); 53 self.state = STATE_TOP; 54 if (self.spawnflags & DOOR_TOGGLE) 55 return; // don't come down automatically 56 self.think = door_go_down; 57 self.nextthink = self.ltime + self.wait; 58}; 59 60void() door_hit_bottom = 61{ 62 if (self.noise1 != "") 63 sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); 64 self.state = STATE_BOTTOM; 65}; 66 67void() door_go_down = 68{ 69 if (self.noise2 != "") 70 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); 71 if (self.max_health) 72 { 73 self.takedamage = DAMAGE_YES; 74 self.health = self.max_health; 75 self.havocattack = TRUE; 76 } 77 78 self.state = STATE_DOWN; 79 SUB_CalcMove (self.pos1, self.speed, door_hit_bottom); 80}; 81 82void() door_go_up = 83{ 84 if (self.state == STATE_UP) 85 return; // allready going up 86 87 if (self.state == STATE_TOP) 88 { // reset top wait time 89 self.nextthink = self.ltime + self.wait; 90 return; 91 } 92 93 if (self.noise2 != "") 94 sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); 95 self.state = STATE_UP; 96 SUB_CalcMove (self.pos2, self.speed, door_hit_top); 97 98 SUB_UseTargets(); 99}; 100 101 102/* 103============================================================================= 104 105ACTIVATION FUNCTIONS 106 107============================================================================= 108*/ 109 110void() door_fire = 111{ 112 local entity oself; 113 local entity starte; 114 115 if (self.owner != self) 116 objerror ("door_fire: self.owner != self"); 117 118// play use key sound 119 120 if (self.items) 121 if (self.noise4 != "") 122 sound (self, CHAN_ITEM, self.noise4, 1, ATTN_NORM); 123 124 self.message = ""; // no more message 125 oself = self; 126 127 if (self.spawnflags & DOOR_TOGGLE) 128 { 129 if (self.state == STATE_UP || self.state == STATE_TOP) 130 { 131 starte = self; 132 do 133 { 134 door_go_down (); 135 self = self.enemy; 136 } while ( (self != starte) && (self != world) ); 137 self = oself; 138 return; 139 } 140 } 141 142// trigger all paired doors 143 starte = self; 144 do 145 { 146 door_go_up (); 147 self = self.enemy; 148 } while ( (self != starte) && (self != world) ); 149 self = oself; 150}; 151 152 153void() door_use = 154{ 155 local entity oself; 156 157 //dprint("door_use (model: ");dprint(self.model);dprint(")\n"); 158 self.message = ""; // door message are for touch only 159 if (self.owner) 160 self.owner.message = ""; 161 if (self.enemy) 162 self.enemy.message = ""; 163 if (self.owner) 164 { 165 oself = self; 166 self = self.owner; 167 door_fire (); 168 self = oself; 169 } 170}; 171 172 173void() door_trigger_touch = 174{ 175 if (other.health < 1) 176 return; 177 178 if (time < self.attack_finished) 179 return; 180 self.attack_finished = time + 1; 181 182 activator = other; 183 184 self = self.owner; 185 door_use (); 186}; 187 188 189void() door_killed = 190{ 191 local entity oself; 192 193 oself = self; 194 self = self.owner; 195 self.health = self.max_health; 196 self.havocattack = TRUE; 197 self.takedamage = DAMAGE_NO; // wil be reset upon return 198 door_use (); 199 self = oself; 200}; 201 202 203/* 204================ 205door_touch 206 207Prints messages and opens key doors 208================ 209*/ 210void() door_touch = 211{ 212 //if (other.classname != "player") 213 if (!other.cantrigger) 214 return; 215 if (self.owner.attack_finished > time) 216 return; 217 218 self.owner.attack_finished = time + 2; 219 220 if (self.owner.message != "") 221 { 222 if (other.flags & FL_CLIENT) 223 centerprint (other, self.owner.message); 224 sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); 225 } 226 227// key door stuff 228 if (!self.items) 229 return; 230 231// FIXME: blink key on player's status bar 232 if ((self.items & other.items) != self.items) 233 { 234 if (self.owner.items == IT_KEY1) 235 { 236 if (world.worldtype == 2) 237 { 238 if (other.flags & FL_CLIENT) 239 centerprint (other, "You need the silver keycard"); 240 if (self.noise3 != "") 241 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 242 } 243 else if (world.worldtype == 1) 244 { 245 if (other.flags & FL_CLIENT) 246 centerprint (other, "You need the silver runekey"); 247 if (self.noise3 != "") 248 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 249 } 250 else if (world.worldtype == 0) 251 { 252 if (other.flags & FL_CLIENT) 253 centerprint (other, "You need the silver key"); 254 if (self.noise3 != "") 255 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 256 } 257 else if (world.worldtype == 5) 258 { 259 if (other.flags & FL_CLIENT) 260 centerprint (other, "You need the silver keycard"); 261 if (self.noise3 != "") 262 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 263 } 264 else if (world.worldtype == 4) 265 { 266 if (other.flags & FL_CLIENT) 267 centerprint (other, "You need the silver runekey"); 268 if (self.noise3 != "") 269 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 270 } 271 else if (world.worldtype == 3) 272 { 273 if (other.flags & FL_CLIENT) 274 centerprint (other, "You need the silver key"); 275 if (self.noise3 != "") 276 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 277 } 278 } 279 else 280 { 281 if (world.worldtype == 2) 282 { 283 if (other.flags & FL_CLIENT) 284 centerprint (other, "You need the gold keycard"); 285 if (self.noise3 != "") 286 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 287 } 288 else if (world.worldtype == 1) 289 { 290 if (other.flags & FL_CLIENT) 291 centerprint (other, "You need the gold runekey"); 292 if (self.noise3 != "") 293 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 294 } 295 else if (world.worldtype == 0) 296 { 297 if (other.flags & FL_CLIENT) 298 centerprint (other, "You need the gold key"); 299 if (self.noise3 != "") 300 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 301 } 302 else if (world.worldtype == 5) 303 { 304 if (other.flags & FL_CLIENT) 305 centerprint (other, "You need the gold keycard"); 306 if (self.noise3 != "") 307 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 308 } 309 else if (world.worldtype == 4) 310 { 311 if (other.flags & FL_CLIENT) 312 centerprint (other, "You need the gold runekey"); 313 if (self.noise3 != "") 314 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 315 } 316 else if (world.worldtype == 3) 317 { 318 if (other.flags & FL_CLIENT) 319 centerprint (other, "You need the gold key"); 320 if (self.noise3 != "") 321 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 322 } 323 } 324 return; 325 } 326 327 // take away 1 key 328 if (self.items == IT_KEY1 && other.keys_silver > 0) 329 other.keys_silver = other.keys_silver - 1; 330 if (self.items == IT_KEY2 && other.keys_gold > 0) 331 other.keys_gold = other.keys_gold - 1; 332 333 // kill the key on scorebar if the player is now out of keys 334 if (other.keys_silver < 1) 335 other.items = other.items - (other.items & IT_KEY1); 336 if (other.keys_gold < 1) 337 other.items = other.items - (other.items & IT_KEY2); 338 339 self.touch = SUB_Null; 340 if (self.enemy) 341 self.enemy.touch = SUB_Null; // get paired door 342 door_use (); 343}; 344 345/* 346============================================================================= 347 348SPAWNING FUNCTIONS 349 350============================================================================= 351*/ 352 353 354entity(vector fmins, vector fmaxs) spawn_field = 355{ 356 local entity trigger; 357 local vector t1, t2; 358 359 trigger = spawn(); 360 trigger.classname = "doortriggerfield"; 361 trigger.movetype = MOVETYPE_NONE; 362 trigger.solid = SOLID_TRIGGER; 363 trigger.owner = self; 364 trigger.touch = door_trigger_touch; 365 366 t1 = fmins; 367 t2 = fmaxs; 368 setsize (trigger, t1 - '60 60 8', t2 + '60 60 8'); 369 return (trigger); 370}; 371 372 373float (entity e1, entity e2) EntitiesTouching = 374{ 375 if (e1.mins_x > e2.maxs_x) 376 return FALSE; 377 if (e1.mins_y > e2.maxs_y) 378 return FALSE; 379 if (e1.mins_z > e2.maxs_z) 380 return FALSE; 381 if (e1.maxs_x < e2.mins_x) 382 return FALSE; 383 if (e1.maxs_y < e2.mins_y) 384 return FALSE; 385 if (e1.maxs_z < e2.mins_z) 386 return FALSE; 387 return TRUE; 388}; 389 390 391/* 392============= 393LinkDoors 394 395 396============= 397*/ 398void() LinkDoors = 399{ 400 local entity t, starte; 401 local vector cmins, cmaxs; 402 403 if (self.enemy) 404 return; // already linked by another door 405 if (self.spawnflags & 4) 406 { 407 self.owner = self.enemy = self; 408 return; // don't want to link this door 409 } 410 411 cmins = self.mins; 412 cmaxs = self.maxs; 413 414 starte = self; 415 t = self; 416 417 do 418 { 419 self.owner = starte; // master door 420 421 if (self.health) 422 { 423 starte.health = self.health; 424 starte.havocattack = TRUE; 425 } 426 if (self.targetname) 427 starte.targetname = self.targetname; 428 if (self.message != "") 429 starte.message = self.message; 430 431 t = find(t, classname, self.classname); 432 if (!t) 433 { 434 self.enemy = starte; // make the chain a loop 435 436 // shootable, fired, or key doors just needed the owner/enemy links, 437 // they don't spawn a field 438 439 self = self.owner; 440 441 if (self.health) 442 return; 443 if (self.targetname) 444 return; 445 if (self.items) 446 return; 447 448 self.owner.trigger_field = spawn_field(cmins, cmaxs); 449 450 return; 451 } 452 453 if (EntitiesTouching(self,t)) 454 { 455 if (t.enemy) 456 objerror ("cross connected doors"); 457 458 self.enemy = t; 459 self = t; 460 461 if (t.mins_x < cmins_x) 462 cmins_x = t.mins_x; 463 if (t.mins_y < cmins_y) 464 cmins_y = t.mins_y; 465 if (t.mins_z < cmins_z) 466 cmins_z = t.mins_z; 467 if (t.maxs_x > cmaxs_x) 468 cmaxs_x = t.maxs_x; 469 if (t.maxs_y > cmaxs_y) 470 cmaxs_y = t.maxs_y; 471 if (t.maxs_z > cmaxs_z) 472 cmaxs_z = t.maxs_z; 473 } 474 } while (1 ); 475 476}; 477 478 479/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE 480if two doors touch, they are assumed to be connected and operate as a unit. 481 482TOGGLE causes the door to wait in both the start and end states for a trigger event. 483 484START_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). 485 486Key doors are allways wait -1. 487 488"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet 489"angle" determines the opening direction 490"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. 491"health" if set, door must be shot open 492"speed" movement speed (100 default) 493"wait" wait before returning (3 default, -1 = never return) 494"lip" lip remaining at end of move (8 default) 495"dmg" damage to inflict when blocked (2 default) 496"sounds" 4970) no sound 4981) stone 4992) base 5003) stone chain 5014) screechy metal 502*/ 503 504void() func_door = 505{ 506 if (!self.deathtype) // map makers can override this 507 self.deathtype = " got in the way"; 508 if (game != GAME_NEXUIZ) 509 { 510 if (world.worldtype == 0) 511 { 512 precache_sound ("doors/medtry.wav"); 513 precache_sound ("doors/meduse.wav"); 514 self.noise3 = "doors/medtry.wav"; 515 self.noise4 = "doors/meduse.wav"; 516 } 517 else if (world.worldtype == 1) 518 { 519 precache_sound ("doors/runetry.wav"); 520 precache_sound ("doors/runeuse.wav"); 521 self.noise3 = "doors/runetry.wav"; 522 self.noise4 = "doors/runeuse.wav"; 523 } 524 else if (world.worldtype == 2) 525 { 526 precache_sound ("doors/basetry.wav"); 527 precache_sound ("doors/baseuse.wav"); 528 self.noise3 = "doors/basetry.wav"; 529 self.noise4 = "doors/baseuse.wav"; 530 } 531 else if (world.worldtype == 3) 532 { 533 precache_sound ("doors/medtry.wav"); 534 precache_sound ("doors/meduse.wav"); 535 self.noise3 = "doors/medtry.wav"; 536 self.noise4 = "doors/meduse.wav"; 537 } 538 else if (world.worldtype == 4) 539 { 540 precache_sound ("doors/runetry.wav"); 541 precache_sound ("doors/runeuse.wav"); 542 self.noise3 = "doors/runetry.wav"; 543 self.noise4 = "doors/runeuse.wav"; 544 } 545 else if (world.worldtype == 5) 546 { 547 precache_sound ("doors/basetry.wav"); 548 precache_sound ("doors/baseuse.wav"); 549 self.noise3 = "doors/basetry.wav"; 550 self.noise4 = "doors/baseuse.wav"; 551 } 552 else 553 { 554 dprint ("no worldtype set!\n"); 555 } 556 if (self.sounds == 0) 557 { 558 precache_sound ("misc/null.wav"); 559 precache_sound ("misc/null.wav"); 560 self.noise1 = "misc/null.wav"; 561 self.noise2 = "misc/null.wav"; 562 } 563 if (self.sounds == 1) 564 { 565 precache_sound ("doors/drclos4.wav"); 566 precache_sound ("doors/doormv1.wav"); 567 self.noise1 = "doors/drclos4.wav"; 568 self.noise2 = "doors/doormv1.wav"; 569 } 570 if (self.sounds == 2) 571 { 572 precache_sound ("doors/hydro1.wav"); 573 precache_sound ("doors/hydro2.wav"); 574 self.noise2 = "doors/hydro1.wav"; 575 self.noise1 = "doors/hydro2.wav"; 576 } 577 if (self.sounds == 3) 578 { 579 precache_sound ("doors/stndr1.wav"); 580 precache_sound ("doors/stndr2.wav"); 581 self.noise2 = "doors/stndr1.wav"; 582 self.noise1 = "doors/stndr2.wav"; 583 } 584 if (self.sounds == 4) 585 { 586 precache_sound ("doors/ddoor1.wav"); 587 precache_sound ("doors/ddoor2.wav"); 588 self.noise1 = "doors/ddoor2.wav"; 589 self.noise2 = "doors/ddoor1.wav"; 590 } 591 } 592 593 SetMovedir (); 594 595 if (self.health) 596 self.havocattack = TRUE; 597 self.max_health = self.health; 598 self.solid = SOLID_BSP; 599 self.movetype = MOVETYPE_PUSH; 600 setorigin (self, self.origin); 601 setmodel (self, self.model); 602 self.classname = "door"; 603 604 self.blocked = door_blocked; 605 self.use = door_use; 606 607 if (self.spawnflags & DOOR_SILVER_KEY) 608 self.items = IT_KEY1; 609 if (self.spawnflags & DOOR_GOLD_KEY) 610 self.items = IT_KEY2; 611 612 if (!self.speed) 613 self.speed = 100; 614 if (!self.wait) 615 self.wait = 3; 616 if (!self.lip) 617 self.lip = 8; 618 if (!self.dmg) 619 self.dmg = 2; 620 621 self.pos1 = self.origin; 622 self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); 623 624// DOOR_START_OPEN is to allow an entity to be lighted in the closed position 625// but spawn in the open position 626 if (self.spawnflags & DOOR_START_OPEN) 627 { 628 setorigin (self, self.pos2); 629 self.pos2 = self.pos1; 630 self.pos1 = self.origin; 631 } 632 633 self.state = STATE_BOTTOM; 634 635 if (self.health) 636 { 637 self.havocattack = TRUE; 638 self.takedamage = DAMAGE_YES; 639 self.th_die = door_killed; 640 } 641 642 if (self.items) 643 self.wait = -1; 644 645 self.touch = door_touch; 646 647// LinkDoors can't be done until all of the doors have been spawned, so 648// the sizes can be detected properly. 649 self.think = LinkDoors; 650 self.nextthink = self.ltime + 0.1; 651}; 652 653/* 654============================================================================= 655 656SECRET DOORS 657 658============================================================================= 659*/ 660 661void() fd_secret_move1; 662void() fd_secret_move2; 663void() fd_secret_move3; 664void() fd_secret_move4; 665void() fd_secret_move5; 666void() fd_secret_move6; 667void() fd_secret_done; 668 669float SECRET_OPEN_ONCE = 1; // stays open 670float SECRET_1ST_LEFT = 2; // 1st move is left of arrow 671float SECRET_1ST_DOWN = 4; // 1st move is down from arrow 672float SECRET_NO_SHOOT = 8; // only opened by trigger 673float SECRET_YES_SHOOT = 16; // shootable even if targeted 674 675 676void () fd_secret_use = 677{ 678 local float temp; 679 680 self.health = 10000; 681 self.havocattack = TRUE; 682 683 // exit if still moving around... 684 if (self.origin != self.oldorigin) 685 return; 686 687 self.message = ""; // no more message 688 689 SUB_UseTargets(); // fire all targets / killtargets 690 691 if (!(self.spawnflags & SECRET_NO_SHOOT)) 692 { 693 self.th_pain = SUB_Null; 694 self.takedamage = DAMAGE_NO; 695 } 696 self.velocity = VEC_ORIGIN; 697 698 // Make a sound, wait a little... 699 700 if (self.noise1 != "") 701 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); 702 self.nextthink = self.ltime + 0.1; 703 704 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1 705 makevectors(self.mangle); 706 707 if (!self.t_width) 708 { 709 if (self.spawnflags & SECRET_1ST_DOWN) 710 self.t_width = fabs(v_up * self.size); 711 else 712 self.t_width = fabs(v_right * self.size); 713 } 714 715 if (!self.t_length) 716 self.t_length = fabs(v_forward * self.size); 717 718 if (self.spawnflags & SECRET_1ST_DOWN) 719 self.dest1 = self.origin - v_up * self.t_width; 720 else 721 self.dest1 = self.origin + v_right * (self.t_width * temp); 722 723 self.dest2 = self.dest1 + v_forward * self.t_length; 724 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1); 725 if (self.noise2 != "") 726 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); 727}; 728 729// Wait after first movement... 730void () fd_secret_move1 = 731{ 732 self.nextthink = self.ltime + 1.0; 733 self.think = fd_secret_move2; 734 if (self.noise3 != "") 735 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 736}; 737 738// Start moving sideways w/sound... 739void () fd_secret_move2 = 740{ 741 if (self.noise2 != "") 742 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); 743 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3); 744}; 745 746// Wait here until time to go back... 747void () fd_secret_move3 = 748{ 749 if (self.noise3 != "") 750 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 751 if (!(self.spawnflags & SECRET_OPEN_ONCE)) 752 { 753 self.nextthink = self.ltime + self.wait; 754 self.think = fd_secret_move4; 755 } 756}; 757 758// Move backward... 759void () fd_secret_move4 = 760{ 761 if (self.noise2 != "") 762 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); 763 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5); 764}; 765 766// Wait 1 second... 767void () fd_secret_move5 = 768{ 769 self.nextthink = self.ltime + 1.0; 770 self.think = fd_secret_move6; 771 if (self.noise3 != "") 772 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 773}; 774 775void () fd_secret_move6 = 776{ 777 if (self.noise2 != "") 778 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); 779 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done); 780}; 781 782void () fd_secret_done = 783{ 784 if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT) 785 { 786 self.health = 10000; 787 self.takedamage = DAMAGE_YES; 788 self.th_pain = fd_secret_use; 789 self.havocattack = TRUE; 790 } 791 if (self.noise3 != "") 792 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); 793}; 794 795void () secret_blocked = 796{ 797 if (time < self.attack_finished) 798 return; 799 self.attack_finished = time + 0.5; 800 T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic); 801}; 802 803/* 804================ 805secret_touch 806 807Prints messages 808================ 809*/ 810void() secret_touch = 811{ 812 if (activator.classname != "player") 813 return; 814 if (self.attack_finished > time) 815 return; 816 817 self.attack_finished = time + 2; 818 819 if (self.message) 820 { 821 if (other.flags & FL_CLIENT) 822 centerprint (other, self.message); 823 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); 824 } 825}; 826 827 828/*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot 829Basic secret door. Slides back, then to the side. Angle determines direction. 830wait = # of seconds before coming back 8311st_left = 1st move is left of arrow 8321st_down = 1st move is down from arrow 833always_shoot = even if targeted, keep shootable 834t_width = override WIDTH to move back (or height if going down) 835t_length = override LENGTH to move sideways 836"dmg" damage to inflict when blocked (2 default) 837 838If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage. 839"sounds" 8401) medieval 8412) metal 8423) base 843*/ 844 845void () func_door_secret = 846{ 847 if (!self.deathtype) // map makers can override this 848 self.deathtype = " got in the way"; 849 if (game != GAME_NEXUIZ) 850 { 851 if (self.sounds == 0) 852 self.sounds = 3; 853 if (self.sounds == 1) 854 { 855 precache_sound ("doors/latch2.wav"); 856 precache_sound ("doors/winch2.wav"); 857 precache_sound ("doors/drclos4.wav"); 858 self.noise1 = "doors/latch2.wav"; 859 self.noise2 = "doors/winch2.wav"; 860 self.noise3 = "doors/drclos4.wav"; 861 } 862 if (self.sounds == 2) 863 { 864 precache_sound ("doors/airdoor1.wav"); 865 precache_sound ("doors/airdoor2.wav"); 866 self.noise2 = "doors/airdoor1.wav"; 867 self.noise1 = "doors/airdoor2.wav"; 868 self.noise3 = "doors/airdoor2.wav"; 869 } 870 if (self.sounds == 3) 871 { 872 precache_sound ("doors/basesec1.wav"); 873 precache_sound ("doors/basesec2.wav"); 874 self.noise2 = "doors/basesec1.wav"; 875 self.noise1 = "doors/basesec2.wav"; 876 self.noise3 = "doors/basesec2.wav"; 877 } 878 } 879 880 if (!self.dmg) 881 self.dmg = 2; 882 883 // Magic formula... 884 self.mangle = self.angles; 885 self.angles = VEC_ORIGIN; 886 self.solid = SOLID_BSP; 887 self.movetype = MOVETYPE_PUSH; 888 self.classname = "door"; 889 setmodel (self, self.model); 890 setorigin (self, self.origin); 891 892 self.touch = secret_touch; 893 self.blocked = secret_blocked; 894 self.speed = 50; 895 self.use = fd_secret_use; 896 if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT) 897 { 898 self.havocattack = TRUE; 899 self.health = 10000; 900 self.takedamage = DAMAGE_YES; 901 self.th_pain = fd_secret_use; 902 self.th_die = fd_secret_use; 903 } 904 self.oldorigin = self.origin; 905 if (!self.wait) 906 self.wait = 5; // 5 seconds before closing 907}; 908