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