1 /* $Id: switch.c,v 1.10 2004-05-17 21:16:28 btb Exp $ */
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.
17 * New Triggers and Switches.
20 * Revision 1.2 1995/10/31 10:18:10 allender
23 * Revision 1.1 1995/05/16 15:31:21 allender
26 * Revision 2.1 1995/03/21 14:39:08 john
27 * Ifdef'd out the NETWORK code.
29 * Revision 2.0 1995/02/27 11:28:41 john
30 * New version 2.0, which has no anonymous unions, builds with
31 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
33 * Revision 1.51 1995/01/31 15:26:23 rob
34 * Don't trigger matcens in anarchy games.
36 * Revision 1.50 1995/01/26 12:18:26 rob
37 * Changed network_do_frame call.
39 * Revision 1.49 1995/01/18 18:50:35 allender
40 * don't process triggers if in demo playback mode. Fix for Rob to only do
41 * multi_send_endlevel_start if in multi player game
43 * Revision 1.48 1995/01/13 11:59:40 rob
44 * Added palette fade after secret level exit.
46 * Revision 1.47 1995/01/12 17:00:41 rob
47 * Fixed a problem with switches and secret levels.
49 * Revision 1.46 1995/01/12 13:35:11 rob
50 * Added data flush after secret level exit.
52 * Revision 1.45 1995/01/03 15:25:11 rob
53 * Fixed a compile error.
55 * Revision 1.44 1995/01/03 15:12:02 rob
56 * Adding multiplayer switching.
58 * Revision 1.43 1994/11/29 16:52:12 yuan
59 * Removed some obsolete commented out code.
61 * Revision 1.42 1994/11/27 23:15:07 matt
62 * Made changes for new mprintf calling convention
64 * Revision 1.41 1994/11/22 18:36:45 rob
65 * Added new hook for endlevel for secret doors.
67 * Revision 1.40 1994/11/21 17:29:43 matt
68 * Cleaned up sequencing & game saving for secret levels
70 * Revision 1.39 1994/11/19 15:20:32 mike
71 * rip out unused code and data
73 * Revision 1.38 1994/10/25 16:09:52 yuan
76 * Revision 1.37 1994/10/24 16:05:28 matt
77 * Removed clear of fuelcen_control_center_destroyed
79 * Revision 1.36 1994/10/08 14:21:13 matt
82 * Revision 1.35 1994/10/07 12:34:09 matt
83 * Added code fot going to/from secret levels
85 * Revision 1.34 1994/10/05 15:16:10 rob
86 * Used to be that only player #0 could trigger switches, now only the
87 * LOCAL player can do it (and he's expected to tell the other guy with
88 * a com message if its important!)
90 * Revision 1.33 1994/09/24 17:42:03 mike
91 * Kill temporary version of function written by Yuan, replaced by MK.
93 * Revision 1.32 1994/09/24 17:10:00 yuan
94 * Added Matcen triggers.
96 * Revision 1.31 1994/09/23 18:02:21 yuan
97 * Completed wall checking.
99 * Revision 1.30 1994/08/19 20:09:41 matt
100 * Added end-of-level cut scene with external scene
102 * Revision 1.29 1994/08/18 10:47:36 john
103 * Cleaned up game sequencing and player death stuff
104 * in preparation for making the player explode into
107 * Revision 1.28 1994/08/12 22:42:11 john
108 * Took away Player_stats; added Players array.
110 * Revision 1.27 1994/07/02 13:50:44 matt
111 * Cleaned up includes
113 * Revision 1.26 1994/06/27 16:32:25 yuan
114 * Commented out incomplete code...
116 * Revision 1.25 1994/06/27 15:53:27 john
117 * #define'd out the newdemo stuff
120 * Revision 1.24 1994/06/27 15:10:04 yuan
121 * Might mess up triggers.
123 * Revision 1.23 1994/06/24 17:01:43 john
124 * Add VFX support; Took Game Sequencing, like EndGame and stuff and
125 * took it out of game.c and into gameseq.c
127 * Revision 1.22 1994/06/16 16:20:15 john
128 * Made player start out in physics mode; Neatend up game loop a bit.
130 * Revision 1.21 1994/06/15 14:57:22 john
131 * Added triggers to demo recording.
133 * Revision 1.20 1994/06/10 17:44:25 mike
134 * Assert on result of find_connect_side == -1
136 * Revision 1.19 1994/06/08 10:20:15 yuan
137 * Removed unused testing.
140 * Revision 1.18 1994/06/07 13:10:48 yuan
141 * Fixed bug in check trigger... Still working on other bugs.
143 * Revision 1.17 1994/05/30 20:22:04 yuan
146 * Revision 1.16 1994/05/27 10:32:46 yuan
147 * New dialog boxes (Walls and Triggers) added.
150 * Revision 1.15 1994/05/25 18:06:46 yuan
151 * Making new dialog box controls for walls and triggers.
153 * Revision 1.14 1994/05/10 19:05:32 yuan
154 * Made end of level flag rather than menu popping up
156 * Revision 1.13 1994/04/29 15:05:25 yuan
157 * Added menu pop-up at exit trigger.
166 static char rcsid[] = "$Id: switch.c,v 1.10 2004-05-17 21:16:28 btb Exp $";
186 #include "cntrlcen.h"
189 #include "endlevel.h"
200 #include "editor/editor.h"
203 trigger Triggers[MAX_TRIGGERS];
206 //link Links[MAX_WALL_LINKS];
210 fix trigger_time_count=F1_0;
212 //-----------------------------------------------------------------
213 // Initializes all the switches.
220 for (i=0;i<MAX_TRIGGERS;i++)
222 Triggers[i].type = 0;
223 Triggers[i].flags = 0;
224 Triggers[i].num_links = 0;
225 Triggers[i].value = 0;
226 Triggers[i].time = -1;
231 //-----------------------------------------------------------------
232 // Executes a link, attached to a trigger.
233 // Toggles all walls linked to the switch.
234 // Opens doors, Blasts blast walls, turns off illusions.
235 void do_link(sbyte trigger_num)
239 mprintf((0, "Door link!\n"));
241 if (trigger_num != -1) {
242 for (i=0;i<Triggers[trigger_num].num_links;i++) {
243 wall_toggle(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
244 mprintf((0," trigger_num %d : seg %d, side %d\n",
245 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
251 void do_close_door(sbyte trigger_num)
255 mprintf((0, "Door close!\n"));
257 if (trigger_num != -1) {
258 for (i=0;i<Triggers[trigger_num].num_links;i++)
259 wall_close_door(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
263 //turns lighting on. returns true if lights were actually turned on. (they
264 //would not be if they had previously been shot out).
265 int do_light_on(sbyte trigger_num)
269 mprintf((0, "Lighting on!\n"));
271 if (trigger_num != -1) {
272 for (i=0;i<Triggers[trigger_num].num_links;i++) {
274 segnum = Triggers[trigger_num].seg[i];
275 sidenum = Triggers[trigger_num].side[i];
277 //check if tmap2 casts light before turning the light on. This
278 //is to keep us from turning on blown-out lights
279 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
280 ret |= add_light(segnum, sidenum); //any light sets flag
281 enable_flicker(segnum, sidenum);
289 //turns lighting off. returns true if lights were actually turned off. (they
290 //would not be if they had previously been shot out).
291 int do_light_off(sbyte trigger_num)
295 mprintf((0, "Lighting off!\n"));
297 if (trigger_num != -1) {
298 for (i=0;i<Triggers[trigger_num].num_links;i++) {
300 segnum = Triggers[trigger_num].seg[i];
301 sidenum = Triggers[trigger_num].side[i];
303 //check if tmap2 casts light before turning the light off. This
304 //is to keep us from turning off blown-out lights
305 if (TmapInfo[Segments[segnum].sides[sidenum].tmap_num2 & 0x3fff].lighting) {
306 ret |= subtract_light(segnum, sidenum); //any light sets flag
307 disable_flicker(segnum, sidenum);
315 // Unlocks all doors linked to the switch.
316 void do_unlock_doors(sbyte trigger_num)
320 mprintf((0, "Door unlock!\n"));
322 if (trigger_num != -1) {
323 for (i=0;i<Triggers[trigger_num].num_links;i++) {
324 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags &= ~WALL_DOOR_LOCKED;
325 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].keys = KEY_NONE;
330 // Return trigger number if door is controlled by a wall switch, else return -1.
331 int door_is_wall_switched(int wall_num)
335 for (t=0; t<Num_triggers; t++) {
336 for (i=0; i<Triggers[t].num_links; i++) {
337 if (Segments[Triggers[t].seg[i]].sides[Triggers[t].side[i]].wall_num == wall_num) {
338 mprintf((0, "Wall #%i is keyed to trigger #%i, link #%i\n", wall_num, t, i));
347 void flag_wall_switched_doors(void)
351 for (i=0; i<Num_walls; i++) {
352 if (door_is_wall_switched(i))
353 Walls[i].flags |= WALL_WALL_SWITCH;
358 // Locks all doors linked to the switch.
359 void do_lock_doors(sbyte trigger_num)
363 mprintf((0, "Door lock!\n"));
365 if (trigger_num != -1) {
366 for (i=0;i<Triggers[trigger_num].num_links;i++) {
367 Walls[Segments[Triggers[trigger_num].seg[i]].sides[Triggers[trigger_num].side[i]].wall_num].flags |= WALL_DOOR_LOCKED;
372 // Changes walls pointed to by a trigger. returns true if any walls changed
373 int do_change_walls(sbyte trigger_num)
377 mprintf((0, "Wall remove!\n"));
379 if (trigger_num != -1) {
380 for (i=0;i<Triggers[trigger_num].num_links;i++) {
381 segment *segp,*csegp;
385 segp = &Segments[Triggers[trigger_num].seg[i]];
386 side = Triggers[trigger_num].side[i];
388 if (segp->children[side] < 0)
395 csegp = &Segments[segp->children[side]];
396 cside = find_connect_side(segp, csegp);
400 //segp->sides[side].wall_num = -1;
401 //csegp->sides[cside].wall_num = -1;
403 switch (Triggers[trigger_num].type) {
404 case TT_OPEN_WALL: new_wall_type = WALL_OPEN; break;
405 case TT_CLOSE_WALL: new_wall_type = WALL_CLOSED; break;
406 case TT_ILLUSORY_WALL: new_wall_type = WALL_ILLUSION; break;
408 Assert(0); /* new_wall_type unset */
413 if (Walls[segp->sides[side].wall_num].type == new_wall_type &&
414 (cside < 0 || csegp->sides[cside].wall_num < 0 ||
415 Walls[csegp->sides[cside].wall_num].type == new_wall_type))
416 continue; //already in correct state, so skip
420 switch (Triggers[trigger_num].type) {
423 mprintf((0,"Open wall\n"));
425 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
427 compute_center_point_on_side(&pos, segp, side );
428 digi_link_sound_to_pos( SOUND_FORCEFIELD_OFF, segp-Segments, side, &pos, 0, F1_0 );
429 Walls[segp->sides[side].wall_num].type = new_wall_type;
430 digi_kill_sound_linked_to_segment(segp-Segments,side,SOUND_FORCEFIELD_HUM);
431 if (cside > -1 && csegp->sides[cside].wall_num > -1)
433 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
434 digi_kill_sound_linked_to_segment(csegp-Segments, cside, SOUND_FORCEFIELD_HUM);
438 start_wall_cloak(segp,side);
445 mprintf((0,"Close wall\n"));
447 if ((TmapInfo[segp->sides[side].tmap_num].flags & TMI_FORCE_FIELD)) {
449 compute_center_point_on_side(&pos, segp, side );
450 digi_link_sound_to_pos(SOUND_FORCEFIELD_HUM,segp-Segments,side,&pos,1, F1_0/2);
451 Walls[segp->sides[side].wall_num].type = new_wall_type;
452 if (cside > -1 && csegp->sides[cside].wall_num > -1)
453 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
456 start_wall_decloak(segp,side);
459 case TT_ILLUSORY_WALL:
460 mprintf((0,"Illusory wall\n"));
461 Walls[segp->sides[side].wall_num].type = new_wall_type;
462 if (cside > -1 && csegp->sides[cside].wall_num > -1)
463 Walls[csegp->sides[cside].wall_num].type = new_wall_type;
468 kill_stuck_objects(segp->sides[side].wall_num);
469 if (cside > -1 && csegp->sides[cside].wall_num > -1)
470 kill_stuck_objects(csegp->sides[cside].wall_num);
478 void print_trigger_message (int pnum,int trig,int shot,char *message)
480 char *pl; //points to 's' or nothing for plural word
482 if (pnum!=Player_num)
485 pl = (Triggers[trig].num_links>1)?"s":"";
487 if (!(Triggers[trig].flags & TF_NO_MESSAGE) && shot)
488 HUD_init_message (message,pl);
492 void do_matcen(sbyte trigger_num)
496 mprintf((0, "Matcen link!\n"));
498 if (trigger_num != -1) {
499 for (i=0;i<Triggers[trigger_num].num_links;i++) {
500 trigger_matcen(Triggers[trigger_num].seg[i] );
501 mprintf((0," trigger_num %d : seg %d\n",
502 trigger_num, Triggers[trigger_num].seg[i]));
508 void do_il_on(sbyte trigger_num)
512 mprintf((0, "Illusion ON\n"));
514 if (trigger_num != -1) {
515 for (i=0;i<Triggers[trigger_num].num_links;i++) {
516 wall_illusion_on(&Segments[Triggers[trigger_num].seg[i]], Triggers[trigger_num].side[i]);
517 mprintf((0," trigger_num %d : seg %d, side %d\n",
518 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
523 void do_il_off(sbyte trigger_num)
527 mprintf((0, "Illusion OFF\n"));
529 if (trigger_num != -1) {
530 for (i=0;i<Triggers[trigger_num].num_links;i++) {
532 segment *seg = &Segments[Triggers[trigger_num].seg[i]];
533 int side = Triggers[trigger_num].side[i];
535 wall_illusion_off(seg, side);
537 mprintf((0," trigger_num %d : seg %d, side %d\n",
538 trigger_num, Triggers[trigger_num].seg[i], Triggers[trigger_num].side[i]));
540 compute_center_point_on_side(&cp, seg, side );
541 digi_link_sound_to_pos( SOUND_WALL_REMOVED, seg-Segments, side, &cp, 0, F1_0 );
547 extern void EnterSecretLevel(void);
548 extern void ExitSecretLevel(void);
549 extern int p_secret_level_destroyed(void);
551 int wall_is_forcefield(trigger *trig)
555 for (i=0;i<trig->num_links;i++)
556 if ((TmapInfo[Segments[trig->seg[i]].sides[trig->side[i]].tmap_num].flags & TMI_FORCE_FIELD))
559 return (i<trig->num_links);
562 int check_trigger_sub(int trigger_num, int pnum,int shot)
564 trigger *trig = &Triggers[trigger_num];
566 mprintf ((0,"trignum=%d type=%d shot=%d\n",trigger_num,trig->type,shot));
568 if (trig->flags & TF_DISABLED)
569 return 1; //1 means don't send trigger hit to other players
571 if (trig->flags & TF_ONE_SHOT) //if this is a one-shot...
572 trig->flags |= TF_DISABLED; //..then don't let it happen again
574 switch (trig->type) {
578 if (pnum!=Player_num)
581 digi_stop_all(); //kill the sounds
583 if (Current_level_num > 0) {
584 start_endlevel_sequence();
585 mprintf((0,"WOOHOO! (leaving the mine!)\n"));
586 } else if (Current_level_num < 0) {
587 if ((Players[Player_num].shields < 0) || Player_is_dead)
594 nm_messagebox( "Yo!", 1, "You have hit the exit trigger!", "" );
596 Int3(); //level num == 0, but no editor!
602 case TT_SECRET_EXIT: {
607 if (pnum!=Player_num)
610 if ((Players[Player_num].shields < 0) || Player_is_dead)
613 if (Game_mode & GM_MULTI) {
614 HUD_init_message("Secret Level Teleporter disabled in multiplayer!");
615 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
620 truth = p_secret_level_destroyed();
622 if (Newdemo_state == ND_STATE_RECORDING) // record whether we're really going to the secret level
623 newdemo_record_secret_exit_blown(truth);
625 if ((Newdemo_state != ND_STATE_PLAYBACK) && truth) {
626 HUD_init_message("Secret Level destroyed. Exit disabled.");
627 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
633 HUD_init_message("Secret Level Teleporter disabled in Descent 2 Demo");
634 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
638 if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording
639 Newdemo_state = ND_STATE_PAUSED;
641 digi_stop_all(); //kill the sounds
643 digi_play_sample( SOUND_SECRET_EXIT, F1_0 );
644 mprintf((0,"Exiting to secret level\n"));
646 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_MULTI)
647 // -- BOGUS -- IMPOSSIBLE -- multi_send_endlevel_start(1);
648 // -- BOGUS -- IMPOSSIBLE --
649 // -- BOGUS -- IMPOSSIBLE -- if (Game_mode & GM_NETWORK)
650 // -- BOGUS -- IMPOSSIBLE -- network_do_frame(1, 1);
652 gr_palette_fade_out(gr_palette, 32, 0);
654 Control_center_destroyed = 0;
662 do_link(trigger_num);
663 print_trigger_message (pnum,trigger_num,shot,"Door%s opened!");
668 do_close_door(trigger_num);
669 print_trigger_message (pnum,trigger_num,shot,"Door%s closed!");
674 do_unlock_doors(trigger_num);
675 print_trigger_message (pnum,trigger_num,shot,"Door%s unlocked!");
681 do_lock_doors(trigger_num);
682 print_trigger_message (pnum,trigger_num,shot,"Door%s locked!");
687 if (do_change_walls(trigger_num))
689 if (wall_is_forcefield(trig))
690 print_trigger_message (pnum,trigger_num,shot,"Force field%s deactivated!");
692 print_trigger_message (pnum,trigger_num,shot,"Wall%s opened!");
697 if (do_change_walls(trigger_num))
699 if (wall_is_forcefield(trig))
700 print_trigger_message (pnum,trigger_num,shot,"Force field%s activated!");
702 print_trigger_message (pnum,trigger_num,shot,"Wall%s closed!");
706 case TT_ILLUSORY_WALL:
707 //don't know what to say, so say nothing
708 do_change_walls(trigger_num);
712 if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS))
713 do_matcen(trigger_num);
718 do_il_on(trigger_num);
719 print_trigger_message (pnum,trigger_num,shot,"Illusion%s on!");
722 case TT_ILLUSION_OFF:
724 do_il_off(trigger_num);
725 print_trigger_message (pnum,trigger_num,shot,"Illusion%s off!");
729 if (do_light_off(trigger_num))
730 print_trigger_message (pnum,trigger_num,shot,"Lights off!");
734 if (do_light_on(trigger_num))
735 print_trigger_message (pnum,trigger_num,shot,"Lights on!");
747 //-----------------------------------------------------------------
748 // Checks for a trigger whenever an object hits a trigger side.
749 void check_trigger(segment *seg, short side, short objnum,int shot)
751 int wall_num, trigger_num; //, ctrigger_num;
757 if ((objnum == Players[Player_num].objnum) || ((Objects[objnum].type == OBJ_ROBOT) && (Robot_info[Objects[objnum].id].companion))) {
759 if ( Newdemo_state == ND_STATE_RECORDING )
760 newdemo_record_trigger( seg-Segments, side, objnum,shot);
762 wall_num = seg->sides[side].wall_num;
763 if ( wall_num == -1 ) return;
765 trigger_num = Walls[wall_num].trigger;
767 if (trigger_num == -1)
770 //##if ( Newdemo_state == ND_STATE_PLAYBACK ) {
771 //## if (Triggers[trigger_num].type == TT_EXIT) {
772 //## start_endlevel_sequence();
777 if (check_trigger_sub(trigger_num, Player_num,shot))
780 //@@if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) {
781 //@@ Triggers[trigger_num].flags &= ~TRIGGER_ON;
783 //@@ csegp = &Segments[seg->children[side]];
784 //@@ cside = find_connect_side(seg, csegp);
785 //@@ Assert(cside != -1);
787 //@@ wall_num = csegp->sides[cside].wall_num;
788 //@@ if ( wall_num == -1 ) return;
790 //@@ ctrigger_num = Walls[wall_num].trigger;
792 //@@ Triggers[ctrigger_num].flags &= ~TRIGGER_ON;
796 if (Game_mode & GM_MULTI)
797 multi_send_trigger(trigger_num);
802 void triggers_frame_process()
806 for (i=0;i<Num_triggers;i++)
807 if (Triggers[i].time >= 0)
808 Triggers[i].time -= FrameTime;
813 * reads a v29_trigger structure from a CFILE
815 extern void v29_trigger_read(v29_trigger *t, CFILE *fp)
819 t->type = cfile_read_byte(fp);
820 t->flags = cfile_read_short(fp);
821 t->value = cfile_read_fix(fp);
822 t->time = cfile_read_fix(fp);
823 t->link_num = cfile_read_byte(fp);
824 t->num_links = cfile_read_short(fp);
825 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
826 t->seg[i] = cfile_read_short(fp);
827 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
828 t->side[i] = cfile_read_short(fp);
832 * reads a v30_trigger structure from a CFILE
834 extern void v30_trigger_read(v30_trigger *t, CFILE *fp)
838 t->flags = cfile_read_short(fp);
839 t->num_links = cfile_read_byte(fp);
840 t->pad = cfile_read_byte(fp);
841 t->value = cfile_read_fix(fp);
842 t->time = cfile_read_fix(fp);
843 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
844 t->seg[i] = cfile_read_short(fp);
845 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
846 t->side[i] = cfile_read_short(fp);
850 * reads a trigger structure from a CFILE
852 extern void trigger_read(trigger *t, CFILE *fp)
856 t->type = cfile_read_byte(fp);
857 t->flags = cfile_read_byte(fp);
858 t->num_links = cfile_read_byte(fp);
859 t->pad = cfile_read_byte(fp);
860 t->value = cfile_read_fix(fp);
861 t->time = cfile_read_fix(fp);
862 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
863 t->seg[i] = cfile_read_short(fp);
864 for (i=0; i<MAX_WALLS_PER_LINK; i++ )
865 t->side[i] = cfile_read_short(fp);