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