]> icculus.org git repositories - btb/d2x.git/blob - main/switch.c
fix compilation error with --disable-network, move reset_network_objects() from games...
[btb/d2x.git] / main / switch.c
1 /* $Id: switch.c,v 1.9 2003-10-04 03:14:48 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.9 2003-10-04 03:14:48 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                         csegp = &Segments[segp->children[side]];
389                         cside = find_connect_side(segp, csegp);
390                         Assert(cside != -1);
391
392                         //segp->sides[side].wall_num = -1;
393                         //csegp->sides[cside].wall_num = -1;
394
395                         switch (Triggers[trigger_num].type) {
396                                 case TT_OPEN_WALL:              new_wall_type = WALL_OPEN; break;
397                                 case TT_CLOSE_WALL:             new_wall_type = WALL_CLOSED; break;
398                                 case TT_ILLUSORY_WALL:  new_wall_type = WALL_ILLUSION; break;
399                                 default:
400                                         Assert(0); /* new_wall_type unset */
401                                         return(0);
402                                         break;
403                         }
404
405                         if (Walls[segp->sides[side].wall_num].type == new_wall_type && Walls[csegp->sides[cside].wall_num].type == new_wall_type)
406                                 continue;               //already in correct state, so skip
407
408                         ret = 1;
409
410                         switch (Triggers[trigger_num].type) {
411         
412                                 case TT_OPEN_WALL:
413                                         mprintf((0,"Open wall\n"));
414
415                                         if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
416                                                 vms_vector pos;
417                                                 compute_center_point_on_side(&pos, segp, side );
418                                                 digi_link_sound_to_pos( SOUND_FORCEFIELD_OFF, segp-Segments, side, &pos, 0, F1_0 );
419                                                 Walls[segp->sides[side].wall_num].type = new_wall_type;
420                                                 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
421                                                 digi_kill_sound_linked_to_segment(segp-Segments,side,SOUND_FORCEFIELD_HUM);
422                                                 digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
423                                         }
424                                         else
425                                                 start_wall_cloak(segp,side);
426
427                                         ret = 1;
428
429                                         break;
430
431                                 case TT_CLOSE_WALL:
432                                         mprintf((0,"Close wall\n"));
433
434                                         if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
435                                                 vms_vector pos;
436                                                 compute_center_point_on_side(&pos, segp, side );
437                                                 digi_link_sound_to_pos(SOUND_FORCEFIELD_HUM,segp-Segments,side,&pos,1, F1_0/2);
438                                                 Walls[segp->sides[side].wall_num].type = new_wall_type;
439                                                 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
440                                         }
441                                         else
442                                                 start_wall_decloak(segp,side);
443                                         break;
444
445                                 case TT_ILLUSORY_WALL:
446                                         mprintf((0,"Illusory wall\n"));
447                                         Walls[segp->sides[side].wall_num].type = new_wall_type;
448                                         Walls[csegp->sides[cside].wall_num].type = new_wall_type;
449                                         break;
450                         }
451
452
453                         kill_stuck_objects(segp->sides[side].wall_num);
454                         kill_stuck_objects(csegp->sides[cside].wall_num);
455
456                 }
457         }
458
459         return ret;
460 }
461
462 void print_trigger_message (int pnum,int trig,int shot,char *message)
463  {
464         char *pl;               //points to 's' or nothing for plural word
465
466    if (pnum!=Player_num)
467                 return;
468
469         pl = (Triggers[trig].num_links>1)?"s":"";
470
471     if (!(Triggers[trig].flags & TF_NO_MESSAGE) && shot)
472      HUD_init_message (message,pl);
473  }
474
475
476 void do_matcen(sbyte trigger_num)
477 {
478         int i;
479
480         mprintf((0, "Matcen link!\n"));
481
482         if (trigger_num != -1) {
483                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
484                         trigger_matcen(Triggers[trigger_num].seg[i] );
485                         mprintf((0," trigger_num %d : seg %d\n",
486                                 trigger_num, Triggers[trigger_num].seg[i]));
487                 }
488         }
489 }
490
491         
492 void do_il_on(sbyte trigger_num)
493 {
494         int i;
495
496         mprintf((0, "Illusion ON\n"));
497
498         if (trigger_num != -1) {
499                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
500                         wall_illusion_on(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
501                         mprintf((0," trigger_num %d : seg %d, side %d\n",
502                                 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
503                 }
504         }
505 }
506
507 void do_il_off(sbyte trigger_num)
508 {
509         int i;
510         
511         mprintf((0, "Illusion OFF\n"));
512
513         if (trigger_num != -1) {
514                 for (i=0;i<Triggers[trigger_num].num_links;i++) {
515                         vms_vector      cp;
516                         segment         *seg = &Segments[Triggers[trigger_num].seg[i]];
517                         int                     side = Triggers[trigger_num].side[i];
518
519                         wall_illusion_off(seg, side);
520
521                         mprintf((0," trigger_num %d : seg %d, side %d\n",
522                                 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
523
524                         compute_center_point_on_side(&cp, seg, side );
525                         digi_link_sound_to_pos( SOUND_WALL_REMOVED, seg-Segments, side, &cp, 0, F1_0 );
526
527                 }
528         }
529 }
530
531 extern void EnterSecretLevel(void);
532 extern void ExitSecretLevel(void);
533 extern int p_secret_level_destroyed(void);
534
535 int wall_is_forcefield(trigger *trig)
536 {
537         int i;
538
539         for (i=0;i<trig->num_links;i++)
540                 if ((TmapInfo[Segments[trig->seg[i]].sides[trig->side[i]].tmap_num].flags & TMI_FORCE_FIELD))
541                         break;
542
543         return (i<trig->num_links);
544 }
545
546 int check_trigger_sub(int trigger_num, int pnum,int shot)
547 {
548         trigger *trig = &Triggers[trigger_num];
549
550         mprintf ((0,"trignum=%d type=%d shot=%d\n",trigger_num,trig->type,shot));
551
552         if (trig->flags & TF_DISABLED)
553                 return 1;               //1 means don't send trigger hit to other players
554
555         if (trig->flags & TF_ONE_SHOT)          //if this is a one-shot...
556                 trig->flags |= TF_DISABLED;             //..then don't let it happen again
557
558         switch (trig->type) {
559
560                 case TT_EXIT:
561
562                         if (pnum!=Player_num)
563                           break;
564
565                         digi_stop_all();                //kill the sounds
566                         
567                         if (Current_level_num > 0) {
568                                 start_endlevel_sequence();
569                                 mprintf((0,"WOOHOO! (leaving the mine!)\n"));
570                         } else if (Current_level_num < 0) {
571                                 if ((Players[Player_num].shields < 0) || Player_is_dead)
572                                         break;
573
574                                 ExitSecretLevel();
575                                 return 1;
576                         } else {
577                                 #ifdef EDITOR
578                                         nm_messagebox( "Yo!", 1, "You have hit the exit trigger!", "" );
579                                 #else
580                                         Int3();         //level num == 0, but no editor!
581                                 #endif
582                         }
583                         return 1;
584                         break;
585
586                 case TT_SECRET_EXIT: {
587 #ifndef SHAREWARE
588                         int     truth;
589 #endif
590
591                         if (pnum!=Player_num)
592                                 break;
593
594                         if ((Players[Player_num].shields < 0) || Player_is_dead)
595                                 break;
596
597                         if (Game_mode & GM_MULTI) {
598                                 HUD_init_message("Secret Level Teleporter disabled in multiplayer!");
599                                 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
600                                 break;
601                         }
602
603                         #ifndef SHAREWARE
604                         truth = p_secret_level_destroyed();
605
606                         if (Newdemo_state == ND_STATE_RECORDING)                        // record whether we're really going to the secret level
607                                 newdemo_record_secret_exit_blown(truth);
608
609                         if ((Newdemo_state != ND_STATE_PLAYBACK) && truth) {
610                                 HUD_init_message("Secret Level destroyed.  Exit disabled.");
611                                 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
612                                 break;
613                         }
614                         #endif
615
616                         #ifdef SHAREWARE
617                                 HUD_init_message("Secret Level Teleporter disabled in Descent 2 Demo");
618                                 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
619                                 break;
620                         #endif
621
622                         if (Newdemo_state == ND_STATE_RECORDING)                // stop demo recording
623                                 Newdemo_state = ND_STATE_PAUSED;
624
625                         digi_stop_all();                //kill the sounds
626
627                         digi_play_sample( SOUND_SECRET_EXIT, F1_0 );
628                         mprintf((0,"Exiting to secret level\n"));
629
630                         // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_MULTI)
631                         // -- BOGUS -- IMPOSSIBLE --    multi_send_endlevel_start(1);
632                         // -- BOGUS -- IMPOSSIBLE --
633                         // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_NETWORK)
634                         // -- BOGUS -- IMPOSSIBLE --    network_do_frame(1, 1);
635
636                         gr_palette_fade_out(gr_palette, 32, 0);
637                         EnterSecretLevel();
638                         Control_center_destroyed = 0;
639                         return 1;
640                         break;
641
642                 }
643
644                 case TT_OPEN_DOOR:
645                         mprintf((0,"D"));
646                         do_link(trigger_num);
647                         print_trigger_message (pnum,trigger_num,shot,"Door%s opened!");
648                         
649                         break;
650
651                 case TT_CLOSE_DOOR:
652                         do_close_door(trigger_num);
653                         print_trigger_message (pnum,trigger_num,shot,"Door%s closed!");
654                         break;
655
656                 case TT_UNLOCK_DOOR:
657                         mprintf((0,"D"));
658                         do_unlock_doors(trigger_num);
659                         print_trigger_message (pnum,trigger_num,shot,"Door%s unlocked!");
660                         
661                         break;
662         
663                 case TT_LOCK_DOOR:
664                         mprintf((0,"D"));
665                         do_lock_doors(trigger_num);
666                         print_trigger_message (pnum,trigger_num,shot,"Door%s locked!");
667
668                         break;
669         
670                 case TT_OPEN_WALL:
671                         if (do_change_walls(trigger_num))
672                         {
673                                 if (wall_is_forcefield(trig))
674                                         print_trigger_message (pnum,trigger_num,shot,"Force field%s deactivated!");
675                                 else
676                                         print_trigger_message (pnum,trigger_num,shot,"Wall%s opened!");
677                         }
678                         break;
679
680                 case TT_CLOSE_WALL:
681                         if (do_change_walls(trigger_num))
682                         {
683                                 if (wall_is_forcefield(trig))
684                                         print_trigger_message (pnum,trigger_num,shot,"Force field%s activated!");
685                                 else
686                                         print_trigger_message (pnum,trigger_num,shot,"Wall%s closed!");
687                         }
688                         break;
689
690                 case TT_ILLUSORY_WALL:
691                         //don't know what to say, so say nothing
692                         do_change_walls(trigger_num);
693                         break;
694
695                 case TT_MATCEN:
696                         if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS))
697                                 do_matcen(trigger_num);
698                         break;
699         
700                 case TT_ILLUSION_ON:
701                         mprintf((0,"I"));
702                         do_il_on(trigger_num);
703                         print_trigger_message (pnum,trigger_num,shot,"Illusion%s on!");
704                         break;
705         
706                 case TT_ILLUSION_OFF:
707                         mprintf((0,"i"));
708                         do_il_off(trigger_num);
709                         print_trigger_message (pnum,trigger_num,shot,"Illusion%s off!");
710                         break;
711
712                 case TT_LIGHT_OFF:
713                         if (do_light_off(trigger_num))
714                                 print_trigger_message (pnum,trigger_num,shot,"Lights off!");
715                         break;
716
717                 case TT_LIGHT_ON:
718                         if (do_light_on(trigger_num))
719                                 print_trigger_message (pnum,trigger_num,shot,"Lights on!");
720
721                         break;
722
723                 default:
724                         Int3();
725                         break;
726         }
727
728         return 0;
729 }
730
731 //-----------------------------------------------------------------
732 // Checks for a trigger whenever an object hits a trigger side.
733 void check_trigger(segment *seg, short side, short objnum,int shot)
734 {
735         int wall_num, trigger_num;      //, ctrigger_num;
736         //segment *csegp;
737         //short cside;
738
739 //      mprintf(0,"T");
740
741         if ((objnum == Players[Player_num].objnum) || ((Objects[objnum].type == OBJ_ROBOT) && (Robot_info[Objects[objnum].id].companion))) {
742
743                 if ( Newdemo_state == ND_STATE_RECORDING )
744                         newdemo_record_trigger( seg-Segments, side, objnum,shot);
745
746                 wall_num = seg->sides[side].wall_num;
747                 if ( wall_num == -1 ) return;
748                 
749                 trigger_num = Walls[wall_num].trigger;
750
751                 if (trigger_num == -1)
752                         return;
753
754                 //##if ( Newdemo_state == ND_STATE_PLAYBACK ) {
755                 //##    if (Triggers[trigger_num].type == TT_EXIT) {
756                 //##            start_endlevel_sequence();
757                 //##    }
758                 //##    //return;
759                 //##}
760
761                 if (check_trigger_sub(trigger_num, Player_num,shot))
762                         return;
763
764                 //@@if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) {
765                 //@@    Triggers[trigger_num].flags &= ~TRIGGER_ON;
766                 //@@
767                 //@@    csegp = &Segments[seg->children[side]];
768                 //@@    cside = find_connect_side(seg, csegp);
769                 //@@    Assert(cside != -1);
770                 //@@
771                 //@@    wall_num = csegp->sides[cside].wall_num;
772                 //@@    if ( wall_num == -1 ) return;
773                 //@@    
774                 //@@    ctrigger_num = Walls[wall_num].trigger;
775                 //@@
776                 //@@    Triggers[ctrigger_num].flags &= ~TRIGGER_ON;
777                 //@@}
778
779 #ifdef NETWORK
780                 if (Game_mode & GM_MULTI)
781                         multi_send_trigger(trigger_num);
782 #endif
783         }
784 }
785
786 void triggers_frame_process()
787 {
788         int i;
789
790         for (i=0;i<Num_triggers;i++)
791                 if (Triggers[i].time >= 0)
792                         Triggers[i].time -= FrameTime;
793 }
794
795 #ifndef FAST_FILE_IO
796 /*
797  * reads a v29_trigger structure from a CFILE
798  */
799 extern void v29_trigger_read(v29_trigger *t, CFILE *fp)
800 {
801         int i;
802
803         t->type = cfile_read_byte(fp);
804         t->flags = cfile_read_short(fp);
805         t->value = cfile_read_fix(fp);
806         t->time = cfile_read_fix(fp);
807         t->link_num = cfile_read_byte(fp);
808         t->num_links = cfile_read_short(fp);
809         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
810                 t->seg[i] = cfile_read_short(fp);
811         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
812                 t->side[i] = cfile_read_short(fp);
813 }
814
815 /*
816  * reads a v30_trigger structure from a CFILE
817  */
818 extern void v30_trigger_read(v30_trigger *t, CFILE *fp)
819 {
820         int i;
821
822         t->flags = cfile_read_short(fp);
823         t->num_links = cfile_read_byte(fp);
824         t->pad = cfile_read_byte(fp);
825         t->value = cfile_read_fix(fp);
826         t->time = cfile_read_fix(fp);
827         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
828                 t->seg[i] = cfile_read_short(fp);
829         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
830                 t->side[i] = cfile_read_short(fp);
831 }
832
833 /*
834  * reads a trigger structure from a CFILE
835  */
836 extern void trigger_read(trigger *t, CFILE *fp)
837 {
838         int i;
839
840         t->type = cfile_read_byte(fp);
841         t->flags = cfile_read_byte(fp);
842         t->num_links = cfile_read_byte(fp);
843         t->pad = cfile_read_byte(fp);
844         t->value = cfile_read_fix(fp);
845         t->time = cfile_read_fix(fp);
846         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
847                 t->seg[i] = cfile_read_short(fp);
848         for (i=0; i<MAX_WALLS_PER_LINK; i++ )
849                 t->side[i] = cfile_read_short(fp);
850 }
851 #endif