]> icculus.org git repositories - divverent/nexuiz.git/blob - TeamNexuiz/game/gamec/g_triggers.c
Added a Game C folder
[divverent/nexuiz.git] / TeamNexuiz / game / gamec / g_triggers.c
1 \r
2 void() SUB_UseTargets;\r
3 \r
4 void() DelayThink =\r
5 {\r
6         activator = self.enemy;\r
7         SUB_UseTargets ();\r
8         remove(self);\r
9 };\r
10 \r
11 /*\r
12 ==============================\r
13 SUB_UseTargets\r
14 \r
15 the global "activator" should be set to the entity that initiated the firing.\r
16 \r
17 If self.delay is set, a DelayedUse entity will be created that will actually\r
18 do the SUB_UseTargets after that many seconds have passed.\r
19 \r
20 Centerprints any self.message to the activator.\r
21 \r
22 Removes all entities with a targetname that match self.killtarget,\r
23 and removes them, so some events can remove other triggers.\r
24 \r
25 Search for (string)targetname in all entities that\r
26 match (string)self.target and call their .use function\r
27 \r
28 ==============================\r
29 */\r
30 /*void() SUB_UseTargets =\r
31 {\r
32         local entity t, stemp, otemp, act;\r
33 \r
34 //\r
35 // check for a delay\r
36 //\r
37         if (self.delay)\r
38         {\r
39         // create a temp object to fire at a later time\r
40                 t = spawn();\r
41                 t.classname = "DelayedUse";\r
42                 t.nextthink = time + self.delay;\r
43                 t.think = DelayThink;\r
44                 t.enemy = activator;\r
45                 t.message = self.message;\r
46                 t.killtarget = self.killtarget;\r
47                 t.target = self.target;\r
48                 return;\r
49         }\r
50 \r
51 \r
52 //\r
53 // print the message\r
54 //\r
55         if (activator.classname == "player" && self.message != "")\r
56         {\r
57                 centerprint (activator, self.message);\r
58                 if (!self.noise)\r
59                         sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);\r
60         }\r
61 \r
62 //\r
63 // kill the killtagets\r
64 //\r
65         if (self.killtarget)\r
66         {\r
67                 t = world;\r
68                 do\r
69                 {\r
70                         t = find (t, targetname, self.killtarget);\r
71                         if (!t)\r
72                                 return;\r
73                         remove (t);\r
74                 } while ( 1 );\r
75         }\r
76 \r
77 //\r
78 // fire targets\r
79 //\r
80         if (self.target)\r
81         {\r
82                 act = activator;\r
83                 t = world;\r
84                 do\r
85                 {\r
86                         t = find (t, targetname, self.target);\r
87                         if (!t)\r
88                         {\r
89                                 return;\r
90                         }\r
91                         stemp = self;\r
92                         otemp = other;\r
93                         self = t;\r
94                         other = stemp;\r
95                         if (self.use)\r
96                                 self.use ();\r
97                         self = stemp;\r
98                         other = otemp;\r
99                         activator = act;\r
100                 } while ( 1 );\r
101         }\r
102 \r
103 \r
104 };*/\r
105 \r
106 \r
107 \r
108 void() trigger_reactivate =\r
109 {\r
110         self.solid = SOLID_TRIGGER;\r
111 };\r
112 \r
113 //=============================================================================\r
114 \r
115 float   SPAWNFLAG_NOMESSAGE = 1;\r
116 float   SPAWNFLAG_NOTOUCH = 1;\r
117 \r
118 // the wait time has passed, so set back up for another activation\r
119 void() multi_wait =\r
120 {\r
121         if (self.max_health)\r
122         {\r
123                 self.health = self.max_health;\r
124                 self.takedamage = DAMAGE_YES;\r
125                 self.solid = SOLID_BBOX;\r
126         }\r
127 };\r
128 \r
129 \r
130 // the trigger was just touched/killed/used\r
131 // self.enemy should be set to the activator so it can be held through a delay\r
132 // so wait for the delay time before firing\r
133 /*void() multi_trigger =\r
134 {\r
135         if (self.nextthink > time)\r
136         {\r
137                 return;         // allready been triggered\r
138         }\r
139 \r
140         if (self.classname == "trigger_secret")\r
141         {\r
142                 if (self.enemy.classname != "player")\r
143                         return;\r
144                 found_secrets = found_secrets + 1;\r
145                 WriteByte (MSG_ALL, SVC_FOUNDSECRET);\r
146         }\r
147 \r
148         if (self.noise)\r
149                 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);\r
150 \r
151 // don't trigger again until reset\r
152         self.takedamage = DAMAGE_NO;\r
153 \r
154         activator = self.enemy;\r
155 \r
156         SUB_UseTargets();\r
157 \r
158         if (self.wait > 0)\r
159         {\r
160                 self.think = multi_wait;\r
161                 self.nextthink = time + self.wait;\r
162         }\r
163         else\r
164         {       // we can't just remove (self) here, because this is a touch function\r
165                 // called wheil C code is looping through area links...\r
166                 self.touch = SUB_Null;\r
167 \r
168                 self.nextthink = time + 0.1;\r
169                 self.think = SUB_Remove;\r
170         }\r
171 };*/\r
172 \r
173 void() multi_trigger = \r
174 {\r
175         if (self.nextthink > time)\r
176         {\r
177                 return;\r
178         }\r
179         if (self.classname == "trigger_secret")\r
180         {\r
181                 if (self.enemy.classname != "player")\r
182                 {\r
183                         return;\r
184                 }\r
185                 found_secrets = found_secrets + TF_FLARE_OFF;\r
186                 WriteByte(2, 28);\r
187         }\r
188         if (self.noise)\r
189         {\r
190                 sound(self, 2, self.noise, TF_FLARE_OFF, TF_FLARE_OFF);\r
191         }\r
192         self.takedamage = TF_FLARE_LIT;\r
193         activator = self.enemy;\r
194         SUB_UseTargets();\r
195         if (self.wait > TF_FLARE_LIT)\r
196         {\r
197                 self.think = multi_wait;\r
198                 self.nextthink = time + self.wait;\r
199         }\r
200         else\r
201         {\r
202                 self.touch = SUB_Null;\r
203                 self.nextthink = time + 0.1;\r
204                 self.think = SUB_Remove;\r
205         }\r
206 };\r
207 \r
208 void() multi_use =\r
209 {\r
210         self.enemy = activator;\r
211         multi_trigger();\r
212 };\r
213 \r
214 void() multi_touch =\r
215 {\r
216         if (other.classname != "player")\r
217                 return;\r
218 \r
219 // if the trigger has an angles field, check player's facing direction\r
220         if (self.movedir != '0 0 0')\r
221         {\r
222                 makevectors (other.angles);\r
223                 if (v_forward * self.movedir < 0)\r
224                         return;         // not facing the right way\r
225         }\r
226 \r
227         self.enemy = other;\r
228         multi_trigger ();\r
229 };\r
230 \r
231 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)\r
232 {\r
233         if (!self.takedamage)\r
234                 return;\r
235         self.health = self.health - damage;\r
236         if (self.health <= 0)\r
237         {\r
238                 self.enemy = attacker;\r
239                 multi_trigger();\r
240         }\r
241 }\r
242 \r
243 /*QUAKED trigger_multiple (.5 .5 .5) ? notouch\r
244 Variable sized repeatable trigger.  Must be targeted at one or more entities.  If "health" is set, the trigger must be killed to activate each time.\r
245 If "delay" is set, the trigger waits some time after activating before firing.\r
246 "wait" : Seconds between triggerings. (.2 default)\r
247 If notouch is set, the trigger is only fired by other entities, not by touching.\r
248 NOTOUCH has been obsoleted by trigger_relay!\r
249 sounds\r
250 1)      secret\r
251 2)      beep beep\r
252 3)      large switch\r
253 4)\r
254 set "message" to text string\r
255 */\r
256 void (float tno) ConvertToGoal;\r
257 void () CheckIfQ3FTrigger;\r
258 void() trigger_multiple =\r
259 {\r
260 /*      if (CheckIfQ3FTrigger() == 1)\r
261         {\r
262                 ConvertToGoal (1);\r
263                 return;\r
264         }\r
265         if (CheckIfQ3FTrigger() == 2)\r
266         {\r
267                 ConvertToGoal (2);\r
268                 return;\r
269         }*/\r
270         CheckIfQ3FTrigger ();\r
271 \r
272         if (self.sounds == 1)\r
273         {\r
274                 precache_sound ("misc/secret.wav");\r
275                 self.noise = "misc/secret.wav";\r
276         }\r
277         else if (self.sounds == 2)\r
278         {\r
279                 precache_sound ("misc/talk.wav");\r
280                 self.noise = "misc/talk.wav";\r
281         }\r
282         else if (self.sounds == 3)\r
283         {\r
284                 precache_sound ("misc/trigger1.wav");\r
285                 self.noise = "misc/trigger1.wav";\r
286         }\r
287 \r
288         if (!self.wait)\r
289                 self.wait = 0.2;\r
290         self.use = multi_use;\r
291 \r
292         InitTrigger ();\r
293 \r
294         if (self.health)\r
295         {\r
296                 if (self.spawnflags & SPAWNFLAG_NOTOUCH)\r
297                         objerror ("health and notouch don't make sense\n");\r
298                 self.max_health = self.health;\r
299                 self.event_damage = multi_eventdamage;\r
300                 self.takedamage = DAMAGE_YES;\r
301                 self.solid = SOLID_BBOX;\r
302                 setorigin (self, self.origin);  // make sure it links into the world\r
303         }\r
304         else\r
305         {\r
306                 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )\r
307                 {\r
308                         self.touch = multi_touch;\r
309                 }\r
310         }\r
311 };\r
312 \r
313 \r
314 /*QUAKED trigger_once (.5 .5 .5) ? notouch\r
315 Variable sized trigger. Triggers once, then removes itself.  You must set the key "target" to the name of another object in the level that has a matching\r
316 "targetname".  If "health" is set, the trigger must be killed to activate.\r
317 If notouch is set, the trigger is only fired by other entities, not by touching.\r
318 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.\r
319 if "angle" is set, the trigger will only fire when someone is facing the direction of the angle.  Use "360" for an angle of 0.\r
320 sounds\r
321 1)      secret\r
322 2)      beep beep\r
323 3)      large switch\r
324 4)\r
325 set "message" to text string\r
326 */\r
327 /*void() trigger_once =\r
328 {\r
329         self.wait = -1;\r
330         trigger_multiple();\r
331 };*/\r
332 \r
333 //=============================================================================\r
334 \r
335 /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)\r
336 This fixed size trigger cannot be touched, it can only be fired by other events.  It can contain killtargets, targets, delays, and messages.\r
337 */\r
338 void() trigger_relay =\r
339 {\r
340         self.use = SUB_UseTargets;\r
341 };\r
342 \r
343 \r
344 //=============================================================================\r
345 \r
346 \r
347 void() counter_use =\r
348 {\r
349         self.count = self.count - 1;\r
350         if (self.count < 0)\r
351                 return;\r
352 \r
353         if (self.count != 0)\r
354         {\r
355                 if (activator.classname == "player"\r
356                 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)\r
357                 {\r
358                         if (self.count >= 4)\r
359                                 centerprint (activator, "There are more to go...");\r
360                         else if (self.count == 3)\r
361                                 centerprint (activator, "Only 3 more to go...");\r
362                         else if (self.count == 2)\r
363                                 centerprint (activator, "Only 2 more to go...");\r
364                         else\r
365                                 centerprint (activator, "Only 1 more to go...");\r
366                 }\r
367                 return;\r
368         }\r
369 \r
370         if (activator.classname == "player"\r
371         && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)\r
372                 centerprint(activator, "Sequence completed!");\r
373         self.enemy = activator;\r
374         multi_trigger ();\r
375 };\r
376 \r
377 /*QUAKED trigger_counter (.5 .5 .5) ? nomessage\r
378 Acts as an intermediary for an action that takes multiple inputs.\r
379 \r
380 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.\r
381 \r
382 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.\r
383 */\r
384 void() trigger_counter =\r
385 {\r
386         self.wait = -1;\r
387         if (!self.count)\r
388                 self.count = 2;\r
389 \r
390         self.use = counter_use;\r
391 };\r
392 \r
393 .float triggerhurttime;\r
394 /*void() hurt_touch =\r
395 {\r
396         if (other.takedamage)\r
397         if (other.triggerhurttime < time)\r
398         {\r
399                 other.triggerhurttime = time + 1;\r
400                 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');\r
401         }\r
402 \r
403         return;\r
404 };*/\r
405 \r
406 /*QUAKED trigger_hurt (.5 .5 .5) ?\r
407 Any object touching this will be hurt\r
408 set dmg to damage amount\r
409 defalt dmg = 5\r
410 */\r
411 /*void() trigger_hurt =\r
412 {\r
413         InitTrigger ();\r
414         self.touch = hurt_touch;\r
415         if (!self.dmg)\r
416                 self.dmg = 1000;\r
417         if (!self.message)\r
418                 self.message = "was in the wrong place.";\r
419 };*/\r
420 \r
421 //void() target_speaker_use = {sound(self, CHAN_VOICE, self.noise, 1, 1);}\r
422 //void() target_speaker = {self.use = target_speaker_use;}\r
423 \r
424 void() target_speaker =\r
425 {\r
426 if(self.noise) {\r
427  precache_sound (self.noise);\r
428  ambientsound (self.origin, self.noise, 1, ATTN_STATIC);\r
429 }\r
430 //remove(self);\r
431 };\r
432 \r
433 \r
434 /*\r
435 void() sparksthink =\r
436 {\r
437   self.nextthink = time + 0.1;\r
438 \r
439   if(random() < self.wait) {\r
440     te_spark(self.origin,'0 0 -1',self.cnt);\r
441   }\r
442 }\r
443 \r
444 \r
445 void() func_sparks =\r
446 {\r
447   self.think = sparksthink;\r
448   self.nextthink = time + 0.2;\r
449 \r
450   // self.cnt is the amount of sparks that one burst will spawn\r
451   if(self.cnt < 1) {\r
452     self.cnt = 25.0; // nice default value\r
453   }\r
454 \r
455   // self.wait is the probability that a sparkthink will spawn a spark shower\r
456   // range: 0 - 1, but 0 makes little sense, so...\r
457   if(self.wait < 0.05) {\r
458     self.wait = 0.25; // nice default value\r
459   }\r
460 \r
461   // sound\r
462   if(self.noise) {\r
463     precache_sound (self.noise);\r
464     ambientsound (self.origin, self.noise, 1, ATTN_STATIC);\r
465   }\r
466 }\r
467 */\r
468 \r
469 \r
470 /*\r
471 =============================================================================\r
472 \r
473 SECRET DOORS\r
474 \r
475 =============================================================================\r
476 */\r
477 \r
478 void() fd_secret_move1;\r
479 void() fd_secret_move2;\r
480 void() fd_secret_move3;\r
481 void() fd_secret_move4;\r
482 void() fd_secret_move5;\r
483 void() fd_secret_move6;\r
484 void() fd_secret_done;\r
485 \r
486 float SECRET_OPEN_ONCE = 1;             // stays open\r
487 float SECRET_1ST_LEFT = 2;              // 1st move is left of arrow\r
488 float SECRET_1ST_DOWN = 4;              // 1st move is down from arrow\r
489 float SECRET_NO_SHOOT = 8;              // only opened by trigger\r
490 float SECRET_YES_SHOOT = 16;    // shootable even if targeted\r
491 \r
492 \r
493 void () fd_secret_use =\r
494 {\r
495         local float temp;\r
496 \r
497         self.health = 10000;\r
498         //self.havocattack = TRUE;\r
499 \r
500         // exit if still moving around...\r
501         if (self.origin != self.oldorigin)\r
502                 return;\r
503 \r
504         self.message = ""; // no more message\r
505 \r
506         SUB_UseTargets();                               // fire all targets / killtargets\r
507 \r
508         self.velocity = '0 0 0';\r
509 \r
510         // Make a sound, wait a little...\r
511 \r
512         if (self.noise1 != "")\r
513                 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);\r
514         self.nextthink = self.ltime + 0.1;\r
515 \r
516         temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1\r
517         makevectors(self.mangle);\r
518 \r
519         if (!self.t_width)\r
520         {\r
521                 if (self.spawnflags & SECRET_1ST_DOWN)\r
522                         self.t_width = fabs(v_up * self.size);\r
523                 else\r
524                         self.t_width = fabs(v_right * self.size);\r
525         }\r
526 \r
527         if (!self.t_length)\r
528                 self.t_length = fabs(v_forward * self.size);\r
529 \r
530         if (self.spawnflags & SECRET_1ST_DOWN)\r
531                 self.dest1 = self.origin - v_up * self.t_width;\r
532         else\r
533                 self.dest1 = self.origin + v_right * (self.t_width * temp);\r
534 \r
535         self.dest2 = self.dest1 + v_forward * self.t_length;\r
536         SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);\r
537         if (self.noise2 != "")\r
538                 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);\r
539 };\r
540 \r
541 // Wait after first movement...\r
542 void () fd_secret_move1 =\r
543 {\r
544         self.nextthink = self.ltime + 1.0;\r
545         self.think = fd_secret_move2;\r
546         if (self.noise3 != "")\r
547                 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);\r
548 };\r
549 \r
550 // Start moving sideways w/sound...\r
551 void () fd_secret_move2 =\r
552 {\r
553         if (self.noise2 != "")\r
554                 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);\r
555         SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);\r
556 };\r
557 \r
558 // Wait here until time to go back...\r
559 void () fd_secret_move3 =\r
560 {\r
561         if (self.noise3 != "")\r
562                 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);\r
563         if (!(self.spawnflags & SECRET_OPEN_ONCE))\r
564         {\r
565                 self.nextthink = self.ltime + self.wait;\r
566                 self.think = fd_secret_move4;\r
567         }\r
568 };\r
569 \r
570 // Move backward...\r
571 void () fd_secret_move4 =\r
572 {\r
573         if (self.noise2 != "")\r
574                 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);\r
575         SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);\r
576 };\r
577 \r
578 // Wait 1 second...\r
579 void () fd_secret_move5 =\r
580 {\r
581         self.nextthink = self.ltime + 1.0;\r
582         self.think = fd_secret_move6;\r
583         if (self.noise3 != "")\r
584                 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);\r
585 };\r
586 \r
587 void () fd_secret_move6 =\r
588 {\r
589         if (self.noise2 != "")\r
590                 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);\r
591         SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);\r
592 };\r
593 \r
594 void () fd_secret_done =\r
595 {\r
596         if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)\r
597         {\r
598                 self.health = 10000;\r
599                 self.takedamage = DAMAGE_YES;\r
600                 //self.th_pain = fd_secret_use;\r
601         }\r
602         if (self.noise3 != "")\r
603                 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);\r
604 };\r
605 \r
606 void () secret_blocked =\r
607 {\r
608         if (time < self.attack_finished)\r
609                 return;\r
610         self.attack_finished = time + 0.5;\r
611         //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);\r
612 };\r
613 \r
614 /*\r
615 ==============\r
616 secret_touch\r
617 \r
618 Prints messages\r
619 ================\r
620 */\r
621 void() secret_touch =\r
622 {\r
623         if (activator.classname != "player")\r
624                 return;\r
625         if (self.attack_finished > time)\r
626                 return;\r
627 \r
628         self.attack_finished = time + 2;\r
629 \r
630         if (self.message)\r
631         {\r
632                 if (other.flags & FL_CLIENT)\r
633                         centerprint (other, self.message);\r
634                 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);\r
635         }\r
636 };\r
637 \r
638 \r
639 /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot\r
640 Basic secret door. Slides back, then to the side. Angle determines direction.\r
641 wait  = # of seconds before coming back\r
642 1st_left = 1st move is left of arrow\r
643 1st_down = 1st move is down from arrow\r
644 always_shoot = even if targeted, keep shootable\r
645 t_width = override WIDTH to move back (or height if going down)\r
646 t_length = override LENGTH to move sideways\r
647 "dmg"           damage to inflict when blocked (2 default)\r
648 \r
649 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.\r
650 "sounds"\r
651 1) medieval\r
652 2) metal\r
653 3) base\r
654 */\r
655 \r
656 void () func_door_secret =\r
657 {\r
658         /*if (!self.deathtype) // map makers can override this\r
659                 self.deathtype = " got in the way";*/\r
660 \r
661         if (!self.dmg)\r
662                 self.dmg = 2;\r
663 \r
664         // Magic formula...\r
665         self.mangle = self.angles;\r
666         self.angles = '0 0 0';\r
667         self.solid = SOLID_BSP;\r
668         self.movetype = MOVETYPE_PUSH;\r
669         self.classname = "door";\r
670         setmodel (self, self.model);\r
671         setorigin (self, self.origin);\r
672 \r
673         self.touch = secret_touch;\r
674         self.blocked = secret_blocked;\r
675         self.speed = 50;\r
676         self.use = fd_secret_use;\r
677         if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)\r
678         {\r
679                 self.health = 10000;\r
680                 self.takedamage = DAMAGE_YES;\r
681                 self.event_damage = fd_secret_use;\r
682         }\r
683         self.oldorigin = self.origin;\r
684         if (!self.wait)\r
685                 self.wait = 5;          // 5 seconds before closing\r
686 };\r
687 \r
688 \r
689 // TF DOORS                     // SHOULD MOVE THIS TO SEPERATE TF DOORS FILE\r
690 void() door_go_down;\r
691 void() door_go_up;\r
692 float() DoorShouldOpen;\r
693 \r
694 void() fd_secret_move1;\r
695 void() fd_secret_move2;\r
696 void() fd_secret_move3;\r
697 void() fd_secret_move4;\r
698 void() fd_secret_move5;\r
699 void() fd_secret_move6;\r
700 void() fd_secret_done;\r
701 \r
702 \r
703 void() door_blocked = \r
704 {\r
705         T_Damage(other, self, self, self.dmg);\r
706         if (self.wait >= TF_FLARE_LIT)\r
707         {\r
708                 if (self.state == 3)\r
709                 {\r
710                         door_go_up();\r
711                 }\r
712                 else\r
713                 {\r
714                         door_go_down();\r
715                 }\r
716         }\r
717 };\r
718 \r
719 void() door_hit_top = \r
720 {\r
721         sound(self, 2, self.noise1, TF_FLARE_OFF, TF_FLARE_OFF);\r
722         self.state = TF_FLARE_LIT;\r
723         if (self.spawnflags & 32)\r
724         {\r
725                 return;\r
726         }\r
727         self.think = door_go_down;\r
728         self.nextthink = self.ltime + self.wait;\r
729 };\r
730 \r
731 void() door_hit_bottom = \r
732 {\r
733         self.goal_state = 2;\r
734         sound(self, 2, self.noise1, TF_FLARE_OFF, TF_FLARE_OFF);\r
735         self.state = TF_FLARE_OFF;\r
736 };\r
737 \r
738 void() door_go_down = \r
739 {\r
740         sound(self, 2, self.noise2, TF_FLARE_OFF, TF_FLARE_OFF);\r
741         if (self.max_health)\r
742         {\r
743                 self.takedamage = TF_FLARE_OFF;\r
744                 self.health = self.max_health;\r
745         }\r
746         self.state = 3;\r
747         SUB_CalcMove(self.pos1, self.speed, door_hit_bottom);\r
748 };\r
749 \r
750 void() door_go_up = \r
751 {\r
752         if (self.state == 2)\r
753         {\r
754                 return;\r
755         }\r
756         if (self.state == TF_FLARE_LIT)\r
757         {\r
758                 self.nextthink = self.ltime + self.wait;\r
759                 return;\r
760         }\r
761         sound(self, 2, self.noise2, TF_FLARE_OFF, TF_FLARE_OFF);\r
762         self.state = 2;\r
763         SUB_CalcMove(self.pos2, self.speed, door_hit_top);\r
764         SUB_UseTargets();\r
765 };\r
766 \r
767 void() door_fire = \r
768 {\r
769         local entity oself;\r
770         local entity starte;\r
771         if (self.owner != self)\r
772         {\r
773                 objerror("door_fire: self.owner != self");\r
774         }\r
775         if (self.items)\r
776         {\r
777                 sound(self, 2, self.noise4, TF_FLARE_OFF, TF_FLARE_OFF);\r
778         }\r
779         self.message = string_null;\r
780         oself = self;\r
781         if (self.spawnflags & 32)\r
782         {\r
783                 if (self.state == 2 || self.state == TF_FLARE_LIT)\r
784                 {\r
785                         starte = self;\r
786                         do\r
787                         {\r
788                                 door_go_down();\r
789                                 self = self.enemy;\r
790                         } while (self != starte && self != world);\r
791                         self = oself;\r
792                         return;\r
793                 }\r
794         }\r
795         starte = self;\r
796         do\r
797         {\r
798                 door_go_up();\r
799                 self = self.enemy;\r
800         } while (self != starte && self != world);\r
801         self = oself;\r
802 };\r
803 \r
804 void() door_use = \r
805 {\r
806         if (other.classname == "info_tfgoal")           // Doors by item_tfgoals in q3f maps werent working right\r
807         {                                                                                       //so I added this as a temp fix.\r
808                 return;                                                                 // Note: doors by info_tfgoals will react slower`\r
809         }\r
810         local entity oself;\r
811         self.message = "";\r
812         self.owner.message = "";\r
813         self.enemy.message = "";\r
814         oself = self;\r
815         self = self.owner;\r
816         door_fire();\r
817         self = oself;\r
818 };\r
819 \r
820 void() door_trigger_touch = \r
821 {\r
822         local entity te;\r
823         if (other.health <= TF_FLARE_LIT)\r
824         {\r
825                 return;\r
826         }\r
827         if (!Activated(self, other))\r
828         {\r
829                 if (self.else_goal != TF_FLARE_LIT)\r
830                 {\r
831                         te = Findgoal(self.else_goal);\r
832                         if (te)\r
833                         {\r
834                                 DoResults(te, other, self.goal_result & 2);\r
835                         }\r
836                 }\r
837                 return;\r
838         }\r
839         if (time < self.attack_finished)\r
840         {\r
841                 return;\r
842         }\r
843         self.attack_finished = time + TF_FLARE_OFF;\r
844         activator = other;\r
845         self = self.owner;\r
846         door_use();\r
847 };\r
848 \r
849 void() door_killed = \r
850 {\r
851         local entity oself;\r
852         oself = self;\r
853         self = self.owner;\r
854         self.health = self.max_health;\r
855         self.takedamage = TF_FLARE_LIT;\r
856         door_use();\r
857         self = oself;\r
858 };\r
859 \r
860 void() door_touch = \r
861 {\r
862         local entity te;\r
863         if (other.classname != "player")\r
864         {\r
865                 return;\r
866         }\r
867         if (self.owner.attack_finished > time)\r
868         {\r
869                 return;\r
870         }\r
871         if (!Activated(self, other))\r
872         {\r
873                 if (self.else_goal != TF_FLARE_LIT)\r
874                 {\r
875                         te = Findgoal(self.else_goal);\r
876                         if (te)\r
877                         {\r
878                                 DoResults(te, other, self.goal_result & 2);\r
879                         }\r
880                 }\r
881                 return;\r
882         }\r
883         self.owner.attack_finished = time + 2;\r
884         if (self.owner.message != "")\r
885         {\r
886                 CenterPrint(other, self.owner.message);\r
887                 sound(other, 2, "misc/talk.wav", TF_FLARE_OFF, TF_FLARE_OFF);\r
888         }\r
889         if (!(self.items))\r
890         {\r
891                 return;\r
892         }\r
893         if ((self.items & other.items) != self.items)\r
894         {\r
895                 if (self.owner.items == 131072)\r
896                 {\r
897                         if (world.worldtype == 2)\r
898                         {\r
899                                 CenterPrint(other, "You need the silver keycard");\r
900                                 sound(self, 2, self.noise3, TF_FLARE_OFF, TF_FLARE_OFF);\r
901                         }\r
902                         else\r
903                         {\r
904                                 if (world.worldtype == TF_FLARE_OFF)\r
905                                 {\r
906                                         CenterPrint(other, "You need the silver runekey");\r
907                                         sound(self, 2, self.noise3, TF_FLARE_OFF, TF_FLARE_OFF);\r
908                                 }\r
909                                 else\r
910                                 {\r
911                                         if (world.worldtype == TF_FLARE_LIT)\r
912                                         {\r
913                                                 CenterPrint(other, "You need the silver key");\r
914                                                 sound(self, 2, self.noise3, TF_FLARE_OFF, TF_FLARE_OFF);\r
915                                         }\r
916                                 }\r
917                         }\r
918                 }\r
919                 else\r
920                 {\r
921                         if (world.worldtype == 2)\r
922                         {\r
923                                 CenterPrint(other, "You need the gold keycard\n");\r
924                                 sound(self, 2, self.noise3, TF_FLARE_OFF, TF_FLARE_OFF);\r
925                         }\r
926                         else\r
927                         {\r
928                                 if (world.worldtype == TF_FLARE_OFF)\r
929                                 {\r
930                                         CenterPrint(other, "You need the gold runekey");\r
931                                         sound(self, 2, self.noise3, TF_FLARE_OFF, TF_FLARE_OFF);\r
932                                 }\r
933                                 else\r
934                                 {\r
935                                         if (world.worldtype == TF_FLARE_LIT)\r
936                                         {\r
937                                                 CenterPrint(other, "You need the gold key");\r
938                                                 sound(self, 2, self.noise3, TF_FLARE_OFF, TF_FLARE_OFF);\r
939                                         }\r
940                                 }\r
941                         }\r
942                 }\r
943                 return;\r
944         }\r
945         other.items = other.items - self.items;\r
946         other.tf_items = other.tf_items | self.items;\r
947         if (DoorShouldOpen())\r
948         {\r
949                 self.touch = SUB_Null;\r
950                 if (self.enemy)\r
951                 {\r
952                         self.enemy.touch = SUB_Null;\r
953                 }\r
954                 door_use();\r
955         }\r
956 };\r
957 \r
958 entity(vector fmins, vector fmaxs) spawn_field = \r
959 {\r
960         local entity trigger;\r
961         local vector t1;\r
962         local vector t2;\r
963         trigger = spawn();\r
964         trigger.movetype = TF_FLARE_LIT;\r
965         trigger.solid = TF_FLARE_OFF;\r
966         trigger.owner = self;\r
967         trigger.touch = door_trigger_touch;\r
968         trigger.team_no = self.team_no;\r
969         trigger.playerclass = self.playerclass;\r
970         trigger.items_allowed = self.items_allowed;\r
971         trigger.activate_goal_no = self.activate_goal_no;\r
972         trigger.inactivate_goal_no = self.inactivate_goal_no;\r
973         trigger.remove_goal_no = self.remove_goal_no;\r
974         trigger.restore_goal_no = self.restore_goal_no;\r
975         trigger.activate_group_no = self.activate_group_no;\r
976         trigger.inactivate_group_no = self.inactivate_group_no;\r
977         trigger.remove_group_no = self.remove_group_no;\r
978         trigger.restore_group_no = self.restore_group_no;\r
979         trigger.goal_activation = self.goal_activation;\r
980         trigger.goal_effects = self.goal_effects;\r
981         trigger.goal_result = self.goal_result;\r
982         trigger.goal_group = self.goal_group;\r
983         t1 = fmins;\r
984         t2 = fmaxs;\r
985         setsize(trigger, t1 - '60 60 8', t2 + '60 60 8');\r
986         return trigger;\r
987 };\r
988 \r
989 float(entity e1, entity e2) EntitiesTouching = \r
990 {\r
991         if (e1.mins_x > e2.maxs_x)\r
992         {\r
993                 return TF_FLARE_LIT;\r
994         }\r
995         if (e1.mins_y > e2.maxs_y)\r
996         {\r
997                 return TF_FLARE_LIT;\r
998         }\r
999         if (e1.mins_z > e2.maxs_z)\r
1000         {\r
1001                 return TF_FLARE_LIT;\r
1002         }\r
1003         if (e1.maxs_x < e2.mins_x)\r
1004         {\r
1005                 return TF_FLARE_LIT;\r
1006         }\r
1007         if (e1.maxs_y < e2.mins_y)\r
1008         {\r
1009                 return TF_FLARE_LIT;\r
1010         }\r
1011         if (e1.maxs_z < e2.mins_z)\r
1012         {\r
1013                 return TF_FLARE_LIT;\r
1014         }\r
1015         return TF_FLARE_OFF;\r
1016 };\r
1017 \r
1018 void() LinkDoors = \r
1019 {\r
1020         local entity t;\r
1021         local entity starte;\r
1022         local vector cmins;\r
1023         local vector cmaxs;\r
1024         if (self.enemy)\r
1025         {\r
1026                 return;\r
1027         }\r
1028         if (self.spawnflags & 4)\r
1029         {\r
1030                 self.enemy = self;\r
1031                 self.owner = self;\r
1032                 return;\r
1033         }\r
1034         cmins = self.mins;\r
1035         cmaxs = self.maxs;\r
1036         starte = self;\r
1037         t = self;\r
1038         do\r
1039         {\r
1040                 self.owner = starte;\r
1041                 if (self.health)\r
1042                 {\r
1043                         starte.health = self.health;\r
1044                 }\r
1045                 if (self.targetname)\r
1046                 {\r
1047                         starte.targetname = self.targetname;\r
1048                 }\r
1049                 if (self.message != "")\r
1050                 {\r
1051                         starte.message = self.message;\r
1052                 }\r
1053                 t = find(t, classname, self.classname);\r
1054                 if (!t)\r
1055                 {\r
1056                         self.enemy = starte;\r
1057                         self = self.owner;\r
1058                         if (self.health)\r
1059                         {\r
1060                                 return;\r
1061                         }\r
1062                         if (self.targetname)\r
1063                         {\r
1064                                 return;\r
1065                         }\r
1066                         if (self.items)\r
1067                         {\r
1068                                 return;\r
1069                         }\r
1070                         self.owner.trigger_field = spawn_field(cmins, cmaxs);\r
1071                         return;\r
1072                 }\r
1073                 if (EntitiesTouching(self, t))\r
1074                 {\r
1075                         if (t.enemy)\r
1076                         {\r
1077                                 objerror("cross connected doors");\r
1078                         }\r
1079                         self.enemy = t;\r
1080                         self = t;\r
1081                         if (t.mins_x < cmins_x)\r
1082                         {\r
1083                                 cmins_x = t.mins_x;\r
1084                         }\r
1085                         if (t.mins_y < cmins_y)\r
1086                         {\r
1087                                 cmins_y = t.mins_y;\r
1088                         }\r
1089                         if (t.mins_z < cmins_z)\r
1090                         {\r
1091                                 cmins_z = t.mins_z;\r
1092                         }\r
1093                         if (t.maxs_x > cmaxs_x)\r
1094                         {\r
1095                                 cmaxs_x = t.maxs_x;\r
1096                         }\r
1097                         if (t.maxs_y > cmaxs_y)\r
1098                         {\r
1099                                 cmaxs_y = t.maxs_y;\r
1100                         }\r
1101                         if (t.maxs_z > cmaxs_z)\r
1102                         {\r
1103                                 cmaxs_z = t.maxs_z;\r
1104                         }\r
1105                 }\r
1106         } while (TF_FLARE_OFF);\r
1107 };\r
1108 \r
1109 void() func_door = \r
1110 {\r
1111         if (CheckExistence() == TF_FLARE_LIT)\r
1112         {\r
1113                 dremove(self);\r
1114                 return;\r
1115         }\r
1116 \r
1117         //      Q3F/ETF Map Support\r
1118         if (self.allowteams == "red")\r
1119         {\r
1120                 self.team_no = 2;\r
1121         }\r
1122         if (self.allowteams == "blue")\r
1123         {\r
1124                 self.team_no = 1;\r
1125         }\r
1126 \r
1127         if (world.worldtype == TF_FLARE_LIT)\r
1128         {\r
1129                 precache_sound("doors/medtry.wav");\r
1130                 precache_sound("doors/meduse.wav");\r
1131                 self.noise3 = "doors/medtry.wav";\r
1132                 self.noise4 = "doors/meduse.wav";\r
1133         }\r
1134         else\r
1135         {\r
1136                 if (world.worldtype == TF_FLARE_OFF)\r
1137                 {\r
1138                         precache_sound("doors/runetry.wav");\r
1139                         precache_sound("doors/runeuse.wav");\r
1140                         self.noise3 = "doors/runetry.wav";\r
1141                         self.noise4 = "doors/runeuse.wav";\r
1142                 }\r
1143                 else\r
1144                 {\r
1145                         if (world.worldtype == 2)\r
1146                         {\r
1147                                 precache_sound("doors/basetry.wav");\r
1148                                 precache_sound("doors/baseuse.wav");\r
1149                                 self.noise3 = "doors/basetry.wav";\r
1150                                 self.noise4 = "doors/baseuse.wav";\r
1151                         }\r
1152                         else\r
1153                         {\r
1154                                 dprint("no worldtype set!\n");\r
1155                         }\r
1156                 }\r
1157         }\r
1158         if (self.sounds == TF_FLARE_LIT)\r
1159         {\r
1160                 precache_sound("misc/null.wav");\r
1161                 precache_sound("misc/null.wav");\r
1162                 self.noise1 = "misc/null.wav";\r
1163                 self.noise2 = "misc/null.wav";\r
1164         }\r
1165         if (self.sounds == TF_FLARE_OFF)\r
1166         {\r
1167                 precache_sound("doors/drclos4.wav");\r
1168                 precache_sound("doors/doormv1.wav");\r
1169                 self.noise1 = "doors/drclos4.wav";\r
1170                 self.noise2 = "doors/doormv1.wav";\r
1171         }\r
1172         if (self.sounds == 2)\r
1173         {\r
1174                 precache_sound("doors/hydro1.wav");\r
1175                 precache_sound("doors/hydro2.wav");\r
1176                 self.noise2 = "doors/hydro1.wav";\r
1177                 self.noise1 = "doors/hydro2.wav";\r
1178         }\r
1179         if (self.sounds == 3)\r
1180         {\r
1181                 precache_sound("doors/stndr1.wav");\r
1182                 precache_sound("doors/stndr2.wav");\r
1183                 self.noise2 = "doors/stndr1.wav";\r
1184                 self.noise1 = "doors/stndr2.wav";\r
1185         }\r
1186         if (self.sounds == 4)\r
1187         {\r
1188                 precache_sound("doors/ddoor1.wav");\r
1189                 precache_sound("doors/ddoor2.wav");\r
1190                 self.noise1 = "doors/ddoor2.wav";\r
1191                 self.noise2 = "doors/ddoor1.wav";\r
1192         }\r
1193         if (self.armorclass == TF_FLARE_OFF)\r
1194         {\r
1195                 precache_sound("doors/creekdr1.wav");\r
1196                 precache_sound("doors/creekdr2.wav");\r
1197                 self.noise2 = "doors/creekdr1.wav";\r
1198                 self.noise1 = "doors/creekdr2.wav";\r
1199         }\r
1200         if (self.armorclass == 2)\r
1201         {\r
1202                 precache_sound("doors/metaldr1.wav");\r
1203                 precache_sound("doors/metaldr2.wav");\r
1204                 self.noise2 = "doors/metaldr1.wav";\r
1205                 self.noise1 = "doors/metaldr2.wav";\r
1206         }\r
1207         if (self.armorclass == 3)\r
1208         {\r
1209                 precache_sound("doors/electdr1.wav");\r
1210                 precache_sound("doors/electdr2.wav");\r
1211                 self.noise2 = "doors/electdr1.wav";\r
1212                 self.noise1 = "doors/electdr2.wav";\r
1213         }\r
1214         if (self.armorclass == 4)\r
1215         {\r
1216                 precache_sound("doors/track_st.wav");\r
1217                 precache_sound("doors/track_e.wav");\r
1218                 self.noise2 = "doors/track_st.wav";\r
1219                 self.noise1 = "doors/track_e.wav";\r
1220         }\r
1221         SetMovedir();\r
1222         self.max_health = self.health;\r
1223         self.solid = 4;\r
1224         self.movetype = 7;\r
1225         setorigin(self, self.origin);\r
1226         setmodel(self, self.model);\r
1227         self.classname = "door";\r
1228         self.blocked = door_blocked;\r
1229         self.use = door_use;\r
1230         if (self.spawnflags & 16)\r
1231         {\r
1232                 self.items = 131072;\r
1233         }\r
1234         if (self.spawnflags & 8)\r
1235         {\r
1236                 self.items = 262144;\r
1237         }\r
1238         if (!(self.speed))\r
1239         {\r
1240                 self.speed = 100;\r
1241         }\r
1242         if (!(self.wait))\r
1243         {\r
1244                 self.wait = 3;\r
1245         }\r
1246         if (!(self.lip))\r
1247         {\r
1248                 self.lip = 8;\r
1249         }\r
1250         if (!(self.dmg))\r
1251         {\r
1252                 self.dmg = 2;\r
1253         }\r
1254         self.pos1 = self.origin;\r
1255         self.pos2 = self.pos1 + self.movedir * (fabs(self.movedir * self.size) - self.lip);\r
1256         if (self.spawnflags & TF_FLARE_OFF)\r
1257         {\r
1258                 setorigin(self, self.pos2);\r
1259                 self.pos2 = self.pos1;\r
1260                 self.pos1 = self.origin;\r
1261         }\r
1262         self.state = TF_FLARE_OFF;\r
1263         if (self.health)\r
1264         {\r
1265                 self.takedamage = TF_FLARE_OFF;\r
1266                 self.th_die = door_killed;\r
1267         }\r
1268         if (self.items)\r
1269         {\r
1270                 self.wait = -1;\r
1271         }\r
1272         self.touch = door_touch;\r
1273         self.think = LinkDoors;\r
1274         self.nextthink = self.ltime + 0.1;\r
1275 };\r
1276 \r
1277 // MOVE TO TFTRIGGERS\r
1278 void() trigger_once = \r
1279 {\r
1280         if (CheckExistence() == TF_FLARE_LIT)\r
1281         {\r
1282                 dremove(self);\r
1283                 return;\r
1284         }\r
1285         self.wait = -1;\r
1286         trigger_multiple();\r
1287 };\r
1288 \r
1289 void() hurt_on = \r
1290 {\r
1291         self.solid = TF_FLARE_OFF;\r
1292         self.nextthink = -1;\r
1293 };\r
1294 \r
1295 void() hurt_touch = \r
1296 {\r
1297         local entity te;\r
1298         if (other.is_dead != 0)         // added by xavior to stop killing of dead bodies\r
1299                 return;                                         ////\r
1300         if (other.takedamage)\r
1301         {\r
1302                 if (!Activated(self, other))\r
1303                 {\r
1304                         if (self.else_goal != TF_FLARE_LIT)\r
1305                         {\r
1306                                 te = Findgoal(self.else_goal);\r
1307                                 if (te)\r
1308                                 {\r
1309                                         DoResults(te, other, self.goal_result & 2);\r
1310                                 }\r
1311                         }\r
1312                         return;\r
1313                 }\r
1314                 self.solid = TF_FLARE_LIT;\r
1315                 deathmsg = 36;\r
1316                 TF_T_Damage(other, self, self, self.dmg, TF_FLARE_OFF, TF_FLARE_LIT);\r
1317                 self.think = hurt_on;\r
1318                 self.nextthink = time + TF_FLARE_OFF;\r
1319         }\r
1320 };\r
1321 \r
1322 void() trigger_hurt = \r
1323 {\r
1324         if (self.allowteams == "red")           // Converted to work with q3f/ETF entities\r
1325         {\r
1326                 self.team_no = 2;\r
1327                 self.owned_by = 2;\r
1328         }\r
1329         if (self.allowteams == "blue")\r
1330         {\r
1331                 self.owned_by = 1;\r
1332                 self.team_no = 1;\r
1333         }\r
1334 \r
1335         if (CheckExistence() == TF_FLARE_LIT)\r
1336         {\r
1337                 dremove(self);\r
1338                 return;\r
1339         }\r
1340         InitTrigger();\r
1341         self.touch = hurt_touch;\r
1342         if (!(self.dmg))\r
1343         {\r
1344                 self.dmg = 5;\r
1345         }\r
1346 };\r
1347 \r
1348 \r
1349 // TF SUBS\r
1350 void () SUB_UseTargets =\r
1351 {\r
1352         local entity t;\r
1353         local entity stemp;\r
1354         local entity otemp;\r
1355         local entity act;\r
1356 \r
1357         if (self.dont_do_triggerwork)\r
1358         {\r
1359                 self.dont_do_triggerwork = 0;\r
1360                 return;\r
1361         }\r
1362         if (self.delay)\r
1363         {\r
1364                 t = spawn ();\r
1365                 t.classname = "DelayedUse";\r
1366                 t.nextthink = (time + self.delay);\r
1367                 t.think = DelayThink;\r
1368                 t.enemy = activator;\r
1369                 t.message = self.message;\r
1370                 t.killtarget = self.killtarget;\r
1371                 t.target = self.target;\r
1372                 return;\r
1373         }\r
1374         if (((activator.classname == "player") && (self.message != "")))\r
1375         {\r
1376                 CenterPrint (activator, self.message);\r
1377                 if (!self.noise)\r
1378                 {\r
1379                         sound (activator, 2, "misc/talk.wav", 1, 1);\r
1380                 }\r
1381         }\r
1382         if ((activator.classname == "player"))\r
1383         {\r
1384                 DoGroupWork (self, activator);\r
1385                 DoGoalWork (self, activator);\r
1386         }\r
1387         if (self.killtarget)\r
1388         {\r
1389                 t = world;\r
1390                 do\r
1391                 {\r
1392                         t = find (t, targetname, self.killtarget);\r
1393                         if (!t)\r
1394                         {\r
1395                                 return;\r
1396                         }\r
1397                         remove (t);\r
1398 \r
1399                 } while (1);\r
1400         }\r
1401         if (self.target)\r
1402         {\r
1403                 act = activator;\r
1404                 t = world;\r
1405                 do\r
1406                 {\r
1407                         t = find (t, targetname, self.target);\r
1408                         if (!t)\r
1409                         {\r
1410                                 return;\r
1411                         }\r
1412                         stemp = self;\r
1413                         otemp = other;\r
1414                         self = t;\r
1415                         other = stemp;\r
1416                         if ((self.use != SUB_Null))\r
1417                         {\r
1418                                 if (self.use)\r
1419                                 {\r
1420                                         self.use ();\r
1421                                 }\r
1422                         }\r
1423                         self = stemp;\r
1424                         other = otemp;\r
1425                         activator = act;\r
1426 \r
1427                 } while (1);\r
1428         }\r
1429 };\r
1430 \r