]> icculus.org git repositories - btb/d2x.git/blob - main/switch.c
memset ogl font bitmap data since the copy function leaves some (unused) parts uninit...
[btb/d2x.git] / main / switch.c
1 /* $Id: switch.c,v 1.10 2004-05-17 21:16:28 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * New Triggers and Switches.
18  *
19  * Old Log:
20  * Revision 1.2  1995/10/31  10:18:10  allender
21  * shareware stuff
22  *
23  * Revision 1.1  1995/05/16  15:31:21  allender
24  * Initial revision
25  *
26  * Revision 2.1  1995/03/21  14:39:08  john
27  * Ifdef'd out the NETWORK code.
28  *
29  * Revision 2.0  1995/02/27  11:28:41  john
30  * New version 2.0, which has no anonymous unions, builds with
31  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
32  *
33  * Revision 1.51  1995/01/31  15:26:23  rob
34  * Don't trigger matcens in anarchy games.
35  *
36  * Revision 1.50  1995/01/26  12:18:26  rob
37  * Changed network_do_frame call.
38  *
39  * Revision 1.49  1995/01/18  18:50:35  allender
40  * don't process triggers if in demo playback mode.  Fix for Rob to only do
41  * multi_send_endlevel_start if in multi player game
42  *
43  * Revision 1.48  1995/01/13  11:59:40  rob
44  * Added palette fade after secret level exit.
45  *
46  * Revision 1.47  1995/01/12  17:00:41  rob
47  * Fixed a problem with switches and secret levels.
48  *
49  * Revision 1.46  1995/01/12  13:35:11  rob
50  * Added data flush after secret level exit.
51  *
52  * Revision 1.45  1995/01/03  15:25:11  rob
53  * Fixed a compile error.
54  *
55  * Revision 1.44  1995/01/03  15:12:02  rob
56  * Adding multiplayer switching.
57  *
58  * Revision 1.43  1994/11/29  16:52:12  yuan
59  * Removed some obsolete commented out code.
60  *
61  * Revision 1.42  1994/11/27  23:15:07  matt
62  * Made changes for new mprintf calling convention
63  *
64  * Revision 1.41  1994/11/22  18:36:45  rob
65  * Added new hook for endlevel for secret doors.
66  *
67  * Revision 1.40  1994/11/21  17:29:43  matt
68  * Cleaned up sequencing & game saving for secret levels
69  *
70  * Revision 1.39  1994/11/19  15:20:32  mike
71  * rip out unused code and data
72  *
73  * Revision 1.38  1994/10/25  16:09:52  yuan
74  * Fixed byte bug.
75  *
76  * Revision 1.37  1994/10/24  16:05:28  matt
77  * Removed clear of fuelcen_control_center_destroyed
78  *
79  * Revision 1.36  1994/10/08  14:21:13  matt
80  * Added include
81  *
82  * Revision 1.35  1994/10/07  12:34:09  matt
83  * Added code fot going to/from secret levels
84  *
85  * Revision 1.34  1994/10/05  15:16:10  rob
86  * Used to be that only player #0 could trigger switches, now only the
87  * LOCAL player can do it (and he's expected to tell the other guy with
88  * a com message if its important!)
89  *
90  * Revision 1.33  1994/09/24  17:42:03  mike
91  * Kill temporary version of function written by Yuan, replaced by MK.
92  *
93  * Revision 1.32  1994/09/24  17:10:00  yuan
94  * Added Matcen triggers.
95  *
96  * Revision 1.31  1994/09/23  18:02:21  yuan
97  * Completed wall checking.
98  *
99  * Revision 1.30  1994/08/19  20:09:41  matt
100  * Added end-of-level cut scene with external scene
101  *
102  * Revision 1.29  1994/08/18  10:47:36  john
103  * Cleaned up game sequencing and player death stuff
104  * in preparation for making the player explode into
105  * pieces when dead.
106  *
107  * Revision 1.28  1994/08/12  22:42:11  john
108  * Took away Player_stats; added Players array.
109  *
110  * Revision 1.27  1994/07/02  13:50:44  matt
111  * Cleaned up includes
112  *
113  * Revision 1.26  1994/06/27  16:32:25  yuan
114  * Commented out incomplete code...
115  *
116  * Revision 1.25  1994/06/27  15:53:27  john
117  * #define'd out the newdemo stuff
118  *
119  *
120  * Revision 1.24  1994/06/27  15:10:04  yuan
121  * Might mess up triggers.
122  *
123  * Revision 1.23  1994/06/24  17:01:43  john
124  * Add VFX support; Took Game Sequencing, like EndGame and stuff and
125  * took it out of game.c and into gameseq.c
126  *
127  * Revision 1.22  1994/06/16  16:20:15  john
128  * Made player start out in physics mode; Neatend up game loop a bit.
129  *
130  * Revision 1.21  1994/06/15  14:57:22  john
131  * Added triggers to demo recording.
132  *
133  * Revision 1.20  1994/06/10  17:44:25  mike
134  * Assert on result of find_connect_side == -1
135  *
136  * Revision 1.19  1994/06/08  10:20:15  yuan
137  * Removed unused testing.
138  *
139  *
140  * Revision 1.18  1994/06/07  13:10:48  yuan
141  * Fixed bug in check trigger... Still working on other bugs.
142  *
143  * Revision 1.17  1994/05/30  20:22:04  yuan
144  * New triggers.
145  *
146  * Revision 1.16  1994/05/27  10:32:46  yuan
147  * New dialog boxes (Walls and Triggers) added.
148  *
149  *
150  * Revision 1.15  1994/05/25  18:06:46  yuan
151  * Making new dialog box controls for walls and triggers.
152  *
153  * Revision 1.14  1994/05/10  19:05:32  yuan
154  * Made end of level flag rather than menu popping up
155  *
156  * Revision 1.13  1994/04/29  15:05:25  yuan
157  * Added menu pop-up at exit trigger.
158  *
159  */
160
161 #ifdef HAVE_CONFIG_H
162 #include <conf.h>
163 #endif
164
165 #ifdef RCS
166 static char rcsid[] = "$Id: switch.c,v 1.10 2004-05-17 21:16:28 btb Exp $";
167 #endif
168
169 #include <stdio.h>
170 #include <stdlib.h>
171 #include <math.h>
172 #include <string.h>
173
174 #include "gauges.h"
175 #include "newmenu.h"
176 #include "game.h"
177 #include "switch.h"
178 #include "inferno.h"
179 #include "segment.h"
180 #include "error.h"
181 #include "gameseg.h"
182 #include "mono.h"
183 #include "wall.h"
184 #include "texmap.h"
185 #include "fuelcen.h"
186 #include "cntrlcen.h"
187 #include "newdemo.h"
188 #include "player.h"
189 #include "endlevel.h"
190 #include "gameseq.h"
191 #include "multi.h"
192 #ifdef NETWORK
193 #include "network.h"
194 #endif
195 #include "palette.h"
196 #include "robot.h"
197 #include "bm.h"
198
199 #ifdef EDITOR
200 #include "editor/editor.h"
201 #endif
202
203 trigger Triggers[MAX_TRIGGERS];
204 int Num_triggers;
205
206 //link Links[MAX_WALL_LINKS];
207 //int Num_links;
208
209 #ifdef EDITOR
210 fix trigger_time_count=F1_0;
211
212 //-----------------------------------------------------------------
213 // Initializes all the switches.
214 void trigger_init()
215 {
216         int i;
217
218         Num_triggers = 0;
219
220         for (i=0;i<MAX_TRIGGERS;i++)
221                 {
222                 Triggers[i].type = 0;
223                 Triggers[i].flags = 0;
224                 Triggers[i].num_links = 0;
225                 Triggers[i].value = 0;
226                 Triggers[i].time = -1;
227                 }
228 }
229 #endif
230
231 //-----------------------------------------------------------------
232 // Executes a link, attached to a trigger.
233 // Toggles all walls linked to the switch.
234 // Opens doors, Blasts blast walls, turns off illusions.
235 void do_link(sbyte trigger_num)
236 {
237         int i;
238
239         mprintf((0, "Door link!\n"));
240
241         if (trigger_num != -1) {
242                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
243                         wall_toggle(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
244                         mprintf((0," trigger_num %d : seg %d, side %d\n",
245                                 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
246                 }
247         }
248 }
249
250 //close a door
251 void do_close_door(sbyte trigger_num)
252 {
253         int i;
254
255         mprintf((0, "Door close!\n"));
256
257         if (trigger_num != -1) {
258                 for (i=0;i<Triggers[trigger_num].num_links;i++)
259                         wall_close_door(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
260         }
261 }
262
263 //turns lighting on.  returns true if lights were actually turned on. (they
264 //would not be if they had previously been shot out).
265 int do_light_on(sbyte trigger_num)
266 {
267         int i,ret=0;
268
269         mprintf((0, "Lighting on!\n"));
270
271         if (trigger_num != -1) {
272                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
273                         int segnum,sidenum;
274                         segnum = Triggers[trigger_num].seg[i];
275                         sidenum = Triggers[trigger_num].side[i];
276
277                         //check if tmap2 casts light before turning the light on.  This
278                         //is to keep us from turning on blown-out lights
279                         if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
280                                 ret |= add_light(segnum, sidenum);              //any light sets flag
281                                 enable_flicker(segnum, sidenum);
282                         }
283                 }
284         }
285
286         return ret;
287 }
288
289 //turns lighting off.  returns true if lights were actually turned off. (they
290 //would not be if they had previously been shot out).
291 int do_light_off(sbyte trigger_num)
292 {
293         int i,ret=0;
294
295         mprintf((0, "Lighting off!\n"));
296
297         if (trigger_num != -1) {
298                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
299                         int segnum,sidenum;
300                         segnum = Triggers[trigger_num].seg[i];
301                         sidenum = Triggers[trigger_num].side[i];
302
303                         //check if tmap2 casts light before turning the light off.  This
304                         //is to keep us from turning off blown-out lights
305                         if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
306                                 ret |= subtract_light(segnum, sidenum);         //any light sets flag
307                                 disable_flicker(segnum, sidenum);
308                         }
309                 }
310         }
311
312         return ret;
313 }
314
315 // Unlocks all doors linked to the switch.
316 void do_unlock_doors(sbyte trigger_num)
317 {
318         int i;
319
320         mprintf((0, "Door unlock!\n"));
321
322         if (trigger_num != -1) {
323                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
324                         Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags &= ~WALL_DOOR_LOCKED;
325                         Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].keys = KEY_NONE;
326                 }
327         }
328 }
329
330 // Return trigger number if door is controlled by a wall switch, else return -1.
331 int door_is_wall_switched(int wall_num)
332 {
333         int i, t;
334
335         for (t=0; t<Num_triggers; t++) {
336                 for (i=0; i<Triggers[t].num_links; i++) {
337                         if (Segments[Triggers[t].seg[i]].sides[Triggers[t].side[i]].wall_num == wall_num) {
338                                 mprintf((0, "Wall #%i is keyed to trigger #%i, link #%i\n", wall_num, t, i));
339                                 return t;
340                         }
341                 }
342         }
343
344         return -1;
345 }
346
347 void flag_wall_switched_doors(void)
348 {
349         int     i;
350
351         for (i=0; i<Num_walls; i++) {
352                 if (door_is_wall_switched(i))
353                         Walls[i].flags |= WALL_WALL_SWITCH;
354         }
355
356 }
357
358 // Locks all doors linked to the switch.
359 void do_lock_doors(sbyte trigger_num)
360 {
361         int i;
362
363         mprintf((0, "Door lock!\n"));
364
365         if (trigger_num != -1) {
366                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
367                         Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags |= WALL_DOOR_LOCKED;
368                 }
369         }
370 }
371
372 // Changes walls pointed to by a trigger. returns true if any walls changed
373 int do_change_walls(sbyte trigger_num)
374 {
375         int i,ret=0;
376
377         mprintf((0, "Wall remove!\n"));
378
379         if (trigger_num != -1) {
380                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
381                         segment *segp,*csegp;
382                         short side,cside;
383                         int new_wall_type;
384
385                         segp = &Segments[Triggers[trigger_num].seg[i]];
386                         side = Triggers[trigger_num].side[i];
387
388                         if (segp->children[side] < 0)
389                         {
390                                 csegp = NULL;
391                                 cside = -1;
392                         }
393                         else
394                         {
395                                 csegp = &Segments[segp->children[side]];
396                                 cside = find_connect_side(segp, csegp);
397                                 Assert(cside != -1);
398                         }
399
400                         //segp->sides[side].wall_num = -1;
401                         //csegp->sides[cside].wall_num = -1;
402
403                         switch (Triggers[trigger_num].type) {
404                                 case TT_OPEN_WALL:              new_wall_type = WALL_OPEN; break;
405                                 case TT_CLOSE_WALL:             new_wall_type = WALL_CLOSED; break;
406                                 case TT_ILLUSORY_WALL:  new_wall_type = WALL_ILLUSION; break;
407                                 default:
408                                         Assert(0); /* new_wall_type unset */
409                                         return(0);
410                                         break;
411                         }
412
413                         if (Walls[segp->sides[side].wall_num].type == new_wall_type &&
414                             (cside < 0 || csegp->sides[cside].wall_num < 0 ||
415                              Walls[csegp->sides[cside].wall_num].type == new_wall_type))
416                                 continue;               //already in correct state, so skip
417
418                         ret = 1;
419
420                         switch (Triggers[trigger_num].type) {
421         
422                                 case TT_OPEN_WALL:
423                                         mprintf((0,"Open wall\n"));
424
425                                         if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
426                                                 vms_vector pos;
427                                                 compute_center_point_on_side(&pos, segp, side );
428                                                 digi_link_sound_to_pos( SOUND_FORCEFIELD_OFF, segp-Segments, side, &pos, 0, F1_0 );
429                                                 Walls[segp->sides[side].wall_num].type = new_wall_type;
430                                                 digi_kill_sound_linked_to_segment(segp-Segments,side,SOUND_FORCEFIELD_HUM);
431                                                 if (cside > -1 && csegp->sides[cside].wall_num > -1)
432                                                 {
433                                                         Walls[csegp->sides[cside].wall_num].type = new_wall_type;
434                                                         digi_kill_sound_linked_to_segment(csegp-Segments, cside, SOUND_FORCEFIELD_HUM);
435                                                 }
436                                         }
437                                         else
438                                                 start_wall_cloak(segp,side);
439
440                                         ret = 1;
441
442                                         break;
443
444                                 case TT_CLOSE_WALL:
445                                         mprintf((0,"Close wall\n"));
446
447                                         if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
448                                                 vms_vector pos;
449                                                 compute_center_point_on_side(&pos, segp, side );
450                                                 digi_link_sound_to_pos(SOUND_FORCEFIELD_HUM,segp-Segments,side,&pos,1, F1_0/2);
451                                                 Walls[segp->sides[side].wall_num].type = new_wall_type;
452                                                 if (cside > -1 && csegp->sides[cside].wall_num > -1)
453                                                         Walls[csegp->sides[cside].wall_num].type = new_wall_type;
454                                         }
455                                         else
456                                                 start_wall_decloak(segp,side);
457                                         break;
458
459                                 case TT_ILLUSORY_WALL:
460                                         mprintf((0,"Illusory wall\n"));
461                                         Walls[segp->sides[side].wall_num].type = new_wall_type;
462                                         if (cside > -1 && csegp->sides[cside].wall_num > -1)
463                                                 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
464                                         break;
465                         }
466
467
468                         kill_stuck_objects(segp->sides[side].wall_num);
469                         if (cside > -1 && csegp->sides[cside].wall_num > -1)
470                                 kill_stuck_objects(csegp->sides[cside].wall_num);
471
472                 }
473         }
474
475         return ret;
476 }
477
478 void print_trigger_message (int pnum,int trig,int shot,char *message)
479  {
480         char *pl;               //points to 's' or nothing for plural word
481
482    if (pnum!=Player_num)
483                 return;
484
485         pl = (Triggers[trig].num_links>1)?"s":"";
486
487     if (!(Triggers[trig].flags & TF_NO_MESSAGE) && shot)
488      HUD_init_message (message,pl);
489  }
490
491
492 void do_matcen(sbyte trigger_num)
493 {
494         int i;
495
496         mprintf((0, "Matcen link!\n"));
497
498         if (trigger_num != -1) {
499                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
500                         trigger_matcen(Triggers[trigger_num].seg[i] );
501                         mprintf((0," trigger_num %d : seg %d\n",
502                                 trigger_num, Triggers[trigger_num].seg[i]));
503                 }
504         }
505 }
506
507         
508 void do_il_on(sbyte trigger_num)
509 {
510         int i;
511
512         mprintf((0, "Illusion ON\n"));
513
514         if (trigger_num != -1) {
515                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
516                         wall_illusion_on(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
517                         mprintf((0," trigger_num %d : seg %d, side %d\n",
518                                 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
519                 }
520         }
521 }
522
523 void do_il_off(sbyte trigger_num)
524 {
525         int i;
526         
527         mprintf((0, "Illusion OFF\n"));
528
529         if (trigger_num != -1) {
530                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
531                         vms_vector      cp;
532                         segment         *seg = &Segments[Triggers[trigger_num].seg[i]];
533                         int                     side = Triggers[trigger_num].side[i];
534
535                         wall_illusion_off(seg, side);
536
537                         mprintf((0," trigger_num %d : seg %d, side %d\n",
538                                 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
539
540                         compute_center_point_on_side(&cp, seg, side );
541                         digi_link_sound_to_pos( SOUND_WALL_REMOVED, seg-Segments, side, &cp, 0, F1_0 );
542
543                 }
544         }
545 }
546
547 extern void EnterSecretLevel(void);
548 extern void ExitSecretLevel(void);
549 extern int p_secret_level_destroyed(void);
550
551 int wall_is_forcefield(trigger *trig)
552 {
553         int i;
554
555         for (i=0;i<trig->num_links;i++)
556                 if ((TmapInfo[Segments[trig->seg[i]].sides[trig->side[i]].tmap_num].flags & TMI_FORCE_FIELD))
557                         break;
558
559         return (i<trig->num_links);
560 }
561
562 int check_trigger_sub(int trigger_num, int pnum,int shot)
563 {
564         trigger *trig = &Triggers[trigger_num];
565
566         mprintf ((0,"trignum=%d type=%d shot=%d\n",trigger_num,trig->type,shot));
567
568         if (trig->flags & TF_DISABLED)
569                 return 1;               //1 means don't send trigger hit to other players
570
571         if (trig->flags & TF_ONE_SHOT)          //if this is a one-shot...
572                 trig->flags |= TF_DISABLED;             //..then don't let it happen again
573
574         switch (trig->type) {
575
576                 case TT_EXIT:
577
578                         if (pnum!=Player_num)
579                           break;
580
581                         digi_stop_all();                //kill the sounds
582                         
583                         if (Current_level_num > 0) {
584                                 start_endlevel_sequence();
585                                 mprintf((0,"WOOHOO! (leaving the mine!)\n"));
586                         } else if (Current_level_num < 0) {
587                                 if ((Players[Player_num].shields < 0) || Player_is_dead)
588                                         break;
589
590                                 ExitSecretLevel();
591                                 return 1;
592                         } else {
593                                 #ifdef EDITOR
594                                         nm_messagebox( "Yo!", 1, "You have hit the exit trigger!", "" );
595                                 #else
596                                         Int3();         //level num == 0, but no editor!
597                                 #endif
598                         }
599                         return 1;
600                         break;
601
602                 case TT_SECRET_EXIT: {
603 #ifndef SHAREWARE
604                         int     truth;
605 #endif
606
607                         if (pnum!=Player_num)
608                                 break;
609
610                         if ((Players[Player_num].shields < 0) || Player_is_dead)
611                                 break;
612
613                         if (Game_mode & GM_MULTI) {
614                                 HUD_init_message("Secret Level Teleporter disabled in multiplayer!");
615                                 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
616                                 break;
617                         }
618
619                         #ifndef SHAREWARE
620                         truth = p_secret_level_destroyed();
621
622                         if (Newdemo_state == ND_STATE_RECORDING)                        // record whether we're really going to the secret level
623                                 newdemo_record_secret_exit_blown(truth);
624
625                         if ((Newdemo_state != ND_STATE_PLAYBACK) && truth) {
626                                 HUD_init_message("Secret Level destroyed.  Exit disabled.");
627                                 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
628                                 break;
629                         }
630                         #endif
631
632                         #ifdef SHAREWARE
633                                 HUD_init_message("Secret Level Teleporter disabled in Descent 2 Demo");
634                                 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
635                                 break;
636                         #endif
637
638                         if (Newdemo_state == ND_STATE_RECORDING)                // stop demo recording
639                                 Newdemo_state = ND_STATE_PAUSED;
640
641                         digi_stop_all();                //kill the sounds
642
643                         digi_play_sample( SOUND_SECRET_EXIT, F1_0 );
644                         mprintf((0,"Exiting to secret level\n"));
645
646                         // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_MULTI)
647                         // -- BOGUS -- IMPOSSIBLE --    multi_send_endlevel_start(1);
648                         // -- BOGUS -- IMPOSSIBLE --
649                         // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_NETWORK)
650                         // -- BOGUS -- IMPOSSIBLE --    network_do_frame(1, 1);
651
652                         gr_palette_fade_out(gr_palette, 32, 0);
653                         EnterSecretLevel();
654                         Control_center_destroyed = 0;
655                         return 1;
656                         break;
657
658                 }
659
660                 case TT_OPEN_DOOR:
661                         mprintf((0,"D"));
662                         do_link(trigger_num);
663                         print_trigger_message (pnum,trigger_num,shot,"Door%s opened!");
664                         
665                         break;
666
667                 case TT_CLOSE_DOOR:
668                         do_close_door(trigger_num);
669                         print_trigger_message (pnum,trigger_num,shot,"Door%s closed!");
670                         break;
671
672                 case TT_UNLOCK_DOOR:
673                         mprintf((0,"D"));
674                         do_unlock_doors(trigger_num);
675                         print_trigger_message (pnum,trigger_num,shot,"Door%s unlocked!");
676                         
677                         break;
678         
679                 case TT_LOCK_DOOR:
680                         mprintf((0,"D"));
681                         do_lock_doors(trigger_num);
682                         print_trigger_message (pnum,trigger_num,shot,"Door%s locked!");
683
684                         break;
685         
686                 case TT_OPEN_WALL:
687                         if (do_change_walls(trigger_num))
688                         {
689                                 if (wall_is_forcefield(trig))
690                                         print_trigger_message (pnum,trigger_num,shot,"Force field%s deactivated!");
691                                 else
692                                         print_trigger_message (pnum,trigger_num,shot,"Wall%s opened!");
693                         }
694                         break;
695
696                 case TT_CLOSE_WALL:
697                         if (do_change_walls(trigger_num))
698                         {
699                                 if (wall_is_forcefield(trig))
700                                         print_trigger_message (pnum,trigger_num,shot,"Force field%s activated!");
701                                 else
702                                         print_trigger_message (pnum,trigger_num,shot,"Wall%s closed!");
703                         }
704                         break;
705
706                 case TT_ILLUSORY_WALL:
707                         //don't know what to say, so say nothing
708                         do_change_walls(trigger_num);
709                         break;
710
711                 case TT_MATCEN:
712                         if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS))
713                                 do_matcen(trigger_num);
714                         break;
715         
716                 case TT_ILLUSION_ON:
717                         mprintf((0,"I"));
718                         do_il_on(trigger_num);
719                         print_trigger_message (pnum,trigger_num,shot,"Illusion%s on!");
720                         break;
721         
722                 case TT_ILLUSION_OFF:
723                         mprintf((0,"i"));
724                         do_il_off(trigger_num);
725                         print_trigger_message (pnum,trigger_num,shot,"Illusion%s off!");
726                         break;
727
728                 case TT_LIGHT_OFF:
729                         if (do_light_off(trigger_num))
730                                 print_trigger_message (pnum,trigger_num,shot,"Lights off!");
731                         break;
732
733                 case TT_LIGHT_ON:
734                         if (do_light_on(trigger_num))
735                                 print_trigger_message (pnum,trigger_num,shot,"Lights on!");
736
737                         break;
738
739                 default:
740                         Int3();
741                         break;
742         }
743
744         return 0;
745 }
746
747 //-----------------------------------------------------------------
748 // Checks for a trigger whenever an object hits a trigger side.
749 void check_trigger(segment *seg, short side, short objnum,int shot)
750 {
751         int wall_num, trigger_num;      //, ctrigger_num;
752         //segment *csegp;
753         //short cside;
754
755 //      mprintf(0,"T");
756
757         if ((objnum == Players[Player_num].objnum) || ((Objects[objnum].type == OBJ_ROBOT) && (Robot_info[Objects[objnum].id].companion))) {
758
759                 if ( Newdemo_state == ND_STATE_RECORDING )
760                         newdemo_record_trigger( seg-Segments, side, objnum,shot);
761
762                 wall_num = seg->sides[side].wall_num;
763                 if ( wall_num == -1 ) return;
764                 
765                 trigger_num = Walls[wall_num].trigger;
766
767                 if (trigger_num == -1)
768                         return;
769
770                 //##if ( Newdemo_state == ND_STATE_PLAYBACK ) {
771                 //##    if (Triggers[trigger_num].type == TT_EXIT) {
772                 //##            start_endlevel_sequence();
773                 //##    }
774                 //##    //return;
775                 //##}
776
777                 if (check_trigger_sub(trigger_num, Player_num,shot))
778                         return;
779
780                 //@@if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) {
781                 //@@    Triggers[trigger_num].flags &= ~TRIGGER_ON;
782                 //@@
783                 //@@    csegp = &Segments[seg->children[side]];
784                 //@@    cside = find_connect_side(seg, csegp);
785                 //@@    Assert(cside != -1);
786                 //@@
787                 //@@    wall_num = csegp->sides[cside].wall_num;
788                 //@@    if ( wall_num == -1 ) return;
789                 //@@    
790                 //@@    ctrigger_num = Walls[wall_num].trigger;
791                 //@@
792                 //@@    Triggers[ctrigger_num].flags &= ~TRIGGER_ON;
793                 //@@}
794
795 #ifdef NETWORK
796                 if (Game_mode & GM_MULTI)
797                         multi_send_trigger(trigger_num);
798 #endif
799         }
800 }
801
802 void triggers_frame_process()
803 {
804         int i;
805
806         for (i=0;i<Num_triggers;i++)
807                 if (Triggers[i].time >= 0)
808                         Triggers[i].time -= FrameTime;
809 }
810
811 #ifndef FAST_FILE_IO
812 /*
813  * reads a v29_trigger structure from a CFILE
814  */
815 extern void v29_trigger_read(v29_trigger *t, CFILE *fp)
816 {
817         int i;
818
819         t->type = cfile_read_byte(fp);
820         t->flags = cfile_read_short(fp);
821         t->value = cfile_read_fix(fp);
822         t->time = cfile_read_fix(fp);
823         t->link_num = cfile_read_byte(fp);
824         t->num_links = cfile_read_short(fp);
825         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
826                 t->seg[i] = cfile_read_short(fp);
827         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
828                 t->side[i] = cfile_read_short(fp);
829 }
830
831 /*
832  * reads a v30_trigger structure from a CFILE
833  */
834 extern void v30_trigger_read(v30_trigger *t, CFILE *fp)
835 {
836         int i;
837
838         t->flags = cfile_read_short(fp);
839         t->num_links = cfile_read_byte(fp);
840         t->pad = cfile_read_byte(fp);
841         t->value = cfile_read_fix(fp);
842         t->time = cfile_read_fix(fp);
843         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
844                 t->seg[i] = cfile_read_short(fp);
845         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
846                 t->side[i] = cfile_read_short(fp);
847 }
848
849 /*
850  * reads a trigger structure from a CFILE
851  */
852 extern void trigger_read(trigger *t, CFILE *fp)
853 {
854         int i;
855
856         t->type = cfile_read_byte(fp);
857         t->flags = cfile_read_byte(fp);
858         t->num_links = cfile_read_byte(fp);
859         t->pad = cfile_read_byte(fp);
860         t->value = cfile_read_fix(fp);
861         t->time = cfile_read_fix(fp);
862         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
863                 t->seg[i] = cfile_read_short(fp);
864         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
865                 t->side[i] = cfile_read_short(fp);
866 }
867 #endif