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