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