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