1 /* $Id: wall.c,v 1.13 2004-08-28 23:17:45 schaffner 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 * Destroyable wall stuff
26 static char rcsid[] = "$Id: wall.c,v 1.13 2004-08-28 23:17:45 schaffner Exp $";
55 #include "laser.h" // For seeing if a flare is stuck in a wall.
60 #include "editor/editor.h"
63 // Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK.
64 #define BOSS_LOCKED_DOOR_LEVEL 7
65 #define BOSS_LOCKED_DOOR_SEG 595
66 #define BOSS_LOCKED_DOOR_SIDE 5
68 wall Walls[MAX_WALLS]; // Master walls array
69 int Num_walls=0; // Number of walls
71 wclip WallAnims[MAX_WALL_ANIMS]; // Wall animations
73 //--unused-- int walls_bm_num[MAX_WALL_ANIMS];
75 //door Doors[MAX_DOORS]; // Master doors array
77 active_door ActiveDoors[MAX_DOORS];
78 int Num_open_doors; // Number of open doors
80 #define CLOAKING_WALL_TIME f1_0
82 #define MAX_CLOAKING_WALLS 10
83 cloaking_wall CloakingWalls[MAX_CLOAKING_WALLS];
84 int Num_cloaking_walls;
86 //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS];
88 //#define BM_FLAG_TRANSPARENT 1
89 //#define BM_FLAG_SUPER_TRANSPARENT 2
92 char Wall_names[7][10] = {
103 // Function prototypes
104 void kill_stuck_objects(int wallnum);
108 // This function determines whether the current segment/side is transparent
111 int check_transparency( segment * seg, int side )
113 if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) {
114 if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT )
120 if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT )
126 //define these here so I don't have to change wall_is_doorway and run
127 //the risk of screwing it up.
128 #define WID_WALL 2 // 0/1/0 wall
129 #define WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
130 #define WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
131 #define WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
132 #define WID_NO_WALL 5 // 1/0/1 no wall, can fly through
133 #define WID_EXTERNAL 8 // 0/0/0/1 don't see it, dont fly through it
135 //-----------------------------------------------------------------
136 // This function checks whether we can fly through the given side.
137 // In other words, whether or not we have a 'doorway'
141 // WID_RENDPAST_FLAG 4
143 // WID_WALL 2 // 0/1/0 wall
144 // WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
145 // WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
146 // WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
147 // WID_NO_WALL 5 // 1/0/1 no wall, can fly through
148 int wall_is_doorway ( segment * seg, int side )
152 //--Covered by macro // No child.
153 //--Covered by macro if (seg->children[side] == -1)
154 //--Covered by macro return WID_WALL;
156 //--Covered by macro if (seg->children[side] == -2)
157 //--Covered by macro return WID_EXTERNAL_FLAG;
159 //--Covered by macro // No wall present.
160 //--Covered by macro if (seg->sides[side].wall_num == -1)
161 //--Covered by macro return WID_NO_WALL;
163 Assert(seg-Segments>=0 && seg-Segments<=Highest_segment_index);
164 Assert(side>=0 && side<6);
166 type = Walls[seg->sides[side].wall_num].type;
167 flags = Walls[seg->sides[side].wall_num].flags;
169 if (type == WALL_OPEN)
172 if (type == WALL_ILLUSION) {
173 if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF)
176 if (check_transparency( seg, side))
177 return WID_TRANSILLUSORY_WALL;
179 return WID_ILLUSORY_WALL;
183 if (type == WALL_BLASTABLE) {
184 if (flags & WALL_BLASTED)
185 return WID_TRANSILLUSORY_WALL;
187 if (check_transparency( seg, side))
188 return WID_TRANSPARENT_WALL;
193 if (flags & WALL_DOOR_OPENED)
194 return WID_TRANSILLUSORY_WALL;
196 if (type == WALL_CLOAKED)
197 return WID_RENDER_FLAG | WID_RENDPAST_FLAG | WID_CLOAKED_FLAG;
199 state = Walls[seg->sides[side].wall_num].state;
200 if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING))
201 return WID_TRANSPARENT_WALL;
203 // If none of the above flags are set, there is no doorway.
204 if (check_transparency( seg, side))
205 return WID_TRANSPARENT_WALL;
207 return WID_WALL; // There are children behind the door.
211 //-----------------------------------------------------------------
212 // Initializes all the walls (in other words, no special walls)
218 for (i=0;i<MAX_WALLS;i++) {
219 Walls[i].segnum = Walls[i].sidenum = -1;
220 Walls[i].type = WALL_NORMAL;
223 Walls[i].trigger = -1;
224 Walls[i].clip_num = -1;
225 Walls[i].linked_wall = -1;
228 Num_cloaking_walls = 0;
232 //-----------------------------------------------------------------
233 // Initializes one wall.
234 void wall_reset(segment *seg, int side)
238 i = seg->sides[side].wall_num;
241 mprintf((0, "Resetting Illegal Wall\n"));
245 Walls[i].segnum = seg-Segments;
246 Walls[i].sidenum = side;
247 Walls[i].type = WALL_NORMAL;
250 Walls[i].trigger = -1;
251 Walls[i].clip_num = -1;
252 Walls[i].linked_wall = -1;
256 //set the tmap_num or tmap_num2 field for a wall/door
257 void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num)
259 wclip *anim = &WallAnims[anim_num];
260 int tmap = anim->frames[frame_num];
262 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
264 if (anim->flags & WCF_TMAP1) {
265 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap;
266 if ( Newdemo_state == ND_STATE_RECORDING )
267 newdemo_record_wall_set_tmap_num1(seg-Segments,side,csegp-Segments,cside,tmap);
269 Assert(tmap!=0 && seg->sides[side].tmap_num2!=0);
270 seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap;
271 if ( Newdemo_state == ND_STATE_RECORDING )
272 newdemo_record_wall_set_tmap_num2(seg-Segments,side,csegp-Segments,cside,tmap);
277 // -------------------------------------------------------------------------------
278 //when the wall has used all its hitpoints, this will destroy it
279 void blast_blastable_wall(segment *seg, int side)
285 Assert(seg->sides[side].wall_num != -1);
287 Walls[seg->sides[side].wall_num].hps = -1; //say it's blasted
289 csegp = &Segments[seg->children[side]];
290 Connectside = find_connect_side(seg, csegp);
291 Assert(Connectside != -1);
292 cwall_num = csegp->sides[Connectside].wall_num;
293 kill_stuck_objects(seg->sides[side].wall_num);
295 kill_stuck_objects(cwall_num);
297 //if this is an exploding wall, explode it
298 if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES)
299 explode_wall(seg-Segments,side);
301 //if not exploding, set final frame, and make door passable
302 a = Walls[seg->sides[side].wall_num].clip_num;
303 n = WallAnims[a].num_frames;
304 wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1);
305 Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED;
307 Walls[cwall_num].flags |= WALL_BLASTED;
313 //-----------------------------------------------------------------
314 // Destroys a blastable wall.
315 void wall_destroy(segment *seg, int side)
317 Assert(seg->sides[side].wall_num != -1);
318 Assert(seg-Segments != 0);
320 if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
321 blast_blastable_wall( seg, side );
323 Error("Hey bub, you are trying to destroy an indestructable wall.");
326 //-----------------------------------------------------------------
327 // Deteriorate appearance of wall. (Changes bitmap (paste-ons))
328 void wall_damage(segment *seg, int side, fix damage)
330 int a, i, n, cwall_num;
332 if (seg->sides[side].wall_num == -1) {
333 mprintf((0, "Damaging illegal wall\n"));
337 if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE)
340 if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED) && Walls[seg->sides[side].wall_num].hps >= 0)
345 csegp = &Segments[seg->children[side]];
346 Connectside = find_connect_side(seg, csegp);
347 Assert(Connectside != -1);
348 cwall_num = csegp->sides[Connectside].wall_num;
349 Walls[seg->sides[side].wall_num].hps -= damage;
351 Walls[cwall_num].hps -= damage;
353 a = Walls[seg->sides[side].wall_num].clip_num;
354 n = WallAnims[a].num_frames;
356 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) {
357 blast_blastable_wall( seg, side );
359 if (Game_mode & GM_MULTI)
360 multi_send_door_open(seg-Segments, side,Walls[seg->sides[side].wall_num].flags);
365 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*(n-i)/n) {
366 wall_set_tmap_num(seg,side,csegp,Connectside,a,i);
372 //-----------------------------------------------------------------
374 void wall_open_door(segment *seg, int side)
378 int Connectside, wall_num, cwall_num;
381 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
383 w = &Walls[seg->sides[side].wall_num];
384 wall_num = w - Walls;
385 //kill_stuck_objects(seg->sides[side].wall_num);
387 if ((w->state == WALL_DOOR_OPENING) || //already opening
388 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
389 (w->state == WALL_DOOR_OPEN)) //open, & staying open
392 if (w->state == WALL_DOOR_CLOSING) { //closing, so reuse door
398 for (i=0;i<Num_open_doors;i++) { //find door
402 if (d->front_wallnum[0]==w-Walls || d->back_wallnum[0]==wall_num ||
403 (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num)))
407 if (i>=Num_open_doors && (Game_mode & GM_MULTI))
410 Assert(i<Num_open_doors); //didn't find door!
411 Assert( d!=NULL ); // Get John!
413 d->time = WallAnims[w->clip_num].play_time - d->time;
419 else { //create new door
420 Assert(w->state == WALL_DOOR_CLOSED);
422 d = &ActiveDoors[Num_open_doors];
425 Assert( Num_open_doors < MAX_DOORS );
429 w->state = WALL_DOOR_OPENING;
431 // So that door can't be shot while opening
432 csegp = &Segments[seg->children[side]];
433 Connectside = find_connect_side(seg, csegp);
434 Assert(Connectside != -1);
435 cwall_num = csegp->sides[Connectside].wall_num;
437 Walls[cwall_num].state = WALL_DOOR_OPENING;
439 //kill_stuck_objects(csegp->sides[Connectside].wall_num);
441 d->front_wallnum[0] = seg->sides[side].wall_num;
442 d->back_wallnum[0] = cwall_num;
444 Assert( seg-Segments != -1);
446 if (Newdemo_state == ND_STATE_RECORDING) {
447 newdemo_record_door_opening(seg-Segments, side);
450 if (w->linked_wall != -1) {
454 w2 = &Walls[w->linked_wall];
455 seg2 = &Segments[w2->segnum];
457 Assert(w2->linked_wall == seg->sides[side].wall_num);
458 //Assert(!(w2->flags & WALL_DOOR_OPENING || w2->flags & WALL_DOOR_OPENED));
460 w2->state = WALL_DOOR_OPENING;
462 csegp = &Segments[seg2->children[w2->sidenum]];
463 Connectside = find_connect_side(seg2, csegp);
464 Assert(Connectside != -1);
466 Walls[cwall_num].state = WALL_DOOR_OPENING;
469 d->front_wallnum[1] = w->linked_wall;
470 d->back_wallnum[1] = cwall_num;
476 if ( Newdemo_state != ND_STATE_PLAYBACK )
478 // NOTE THE LINK TO ABOVE!!!!
480 compute_center_point_on_side(&cp, seg, side );
481 if (WallAnims[w->clip_num].open_sound > -1 )
482 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
487 //-----------------------------------------------------------------
488 // start the transition from closed -> open wall
489 void start_wall_cloak(segment *seg, int side)
497 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
499 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
501 w = &Walls[seg->sides[side].wall_num];
503 if (w->type == WALL_OPEN || w->state == WALL_DOOR_CLOAKING) //already open or cloaking
506 csegp = &Segments[seg->children[side]];
507 Connectside = find_connect_side(seg, csegp);
508 Assert(Connectside != -1);
509 cwall_num = csegp->sides[Connectside].wall_num;
511 if (w->state == WALL_DOOR_DECLOAKING) { //decloaking, so reuse door
517 for (i=0;i<Num_cloaking_walls;i++) { //find door
519 d = &CloakingWalls[i];
521 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
525 Assert(i<Num_cloaking_walls); //didn't find door!
526 Assert( d!=NULL ); // Get John!
528 d->time = CLOAKING_WALL_TIME - d->time;
531 else if (w->state == WALL_DOOR_CLOSED) { //create new door
532 d = &CloakingWalls[Num_cloaking_walls];
534 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
535 Int3(); //ran out of cloaking wall slots
538 Walls[cwall_num].type = WALL_OPEN;
541 Num_cloaking_walls++;
544 Int3(); //unexpected wall state
548 w->state = WALL_DOOR_CLOAKING;
550 Walls[cwall_num].state = WALL_DOOR_CLOAKING;
552 d->front_wallnum = seg->sides[side].wall_num;
553 d->back_wallnum = cwall_num;
555 Assert( seg-Segments != -1);
557 Assert(w->linked_wall == -1);
559 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
561 compute_center_point_on_side(&cp, seg, side );
562 digi_link_sound_to_pos( SOUND_WALL_CLOAK_ON, seg-Segments, side, &cp, 0, F1_0 );
566 d->front_ls[i] = seg->sides[side].uvls[i].l;
568 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
572 //-----------------------------------------------------------------
573 // start the transition from open -> closed wall
574 void start_wall_decloak(segment *seg, int side)
582 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
584 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
586 w = &Walls[seg->sides[side].wall_num];
588 if (w->type == WALL_CLOSED || w->state == WALL_DOOR_DECLOAKING) //already closed or decloaking
591 if (w->state == WALL_DOOR_CLOAKING) { //cloaking, so reuse door
597 for (i=0;i<Num_cloaking_walls;i++) { //find door
599 d = &CloakingWalls[i];
601 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
605 Assert(i<Num_cloaking_walls); //didn't find door!
606 Assert( d!=NULL ); // Get John!
608 d->time = CLOAKING_WALL_TIME - d->time;
611 else if (w->state == WALL_DOOR_CLOSED) { //create new door
612 d = &CloakingWalls[Num_cloaking_walls];
614 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
615 Int3(); //ran out of cloaking wall slots
616 /* what is this _doing_ here?
617 w->type = WALL_CLOSED;
618 Walls[csegp->sides[Connectside].wall_num].type = WALL_CLOSED;
622 Num_cloaking_walls++;
625 Int3(); //unexpected wall state
629 w->state = WALL_DOOR_DECLOAKING;
631 // So that door can't be shot while opening
632 csegp = &Segments[seg->children[side]];
633 Connectside = find_connect_side(seg, csegp);
634 Assert(Connectside != -1);
635 cwall_num = csegp->sides[Connectside].wall_num;
637 Walls[cwall_num].state = WALL_DOOR_DECLOAKING;
639 d->front_wallnum = seg->sides[side].wall_num;
640 d->back_wallnum = csegp->sides[Connectside].wall_num;
642 Assert( seg-Segments != -1);
644 Assert(w->linked_wall == -1);
646 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
648 compute_center_point_on_side(&cp, seg, side );
649 digi_link_sound_to_pos( SOUND_WALL_CLOAK_OFF, seg-Segments, side, &cp, 0, F1_0 );
653 d->front_ls[i] = seg->sides[side].uvls[i].l;
655 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
659 //-----------------------------------------------------------------
660 // This function closes the specified door and restores the closed
661 // door texture. This is called when the animation is done
662 void wall_close_door_num(int door_num)
668 d = &ActiveDoors[door_num];
670 for (p=0;p<d->n_parts;p++) {
672 int Connectside, side;
673 segment *csegp, *seg;
675 w = &Walls[d->front_wallnum[p]];
677 seg = &Segments[w->segnum];
680 Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall
682 csegp = &Segments[seg->children[side]];
683 Connectside = find_connect_side(seg, csegp);
684 Assert(Connectside != -1);
685 cwall_num = csegp->sides[Connectside].wall_num;
686 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED;
688 Walls[cwall_num].state = WALL_DOOR_CLOSED;
690 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0);
694 for (i=door_num;i<Num_open_doors;i++)
695 ActiveDoors[i] = ActiveDoors[i+1];
701 int check_poke(int objnum,int segnum,int side)
703 object *obj = &Objects[objnum];
705 //note: don't let objects with zero size block door
707 if (obj->size && get_seg_masks(&obj->pos, segnum, obj->size, __FILE__, __LINE__).sidemask & (1 << side))
708 return 1; //pokes through side!
710 return 0; //does not!
714 //returns true of door in unobjstructed (& thus can close)
715 int is_door_free(segment *seg,int side)
721 csegp = &Segments[seg->children[side]];
722 Connectside = find_connect_side(seg, csegp);
723 Assert(Connectside != -1);
725 //go through each object in each of two segments, and see if
726 //it pokes into the connecting seg
728 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
729 if (Objects[objnum].type!=OBJ_WEAPON && Objects[objnum].type!=OBJ_FIREBALL && check_poke(objnum,seg-Segments,side))
732 for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next)
733 if (Objects[objnum].type!=OBJ_WEAPON && Objects[objnum].type!=OBJ_FIREBALL && check_poke(objnum,csegp-Segments,Connectside))
736 return 1; //doorway is free!
741 //-----------------------------------------------------------------
743 void wall_close_door(segment *seg, int side)
747 int Connectside, wall_num, cwall_num;
750 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
752 w = &Walls[seg->sides[side].wall_num];
753 wall_num = w - Walls;
754 if ((w->state == WALL_DOOR_CLOSING) || //already closing
755 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
756 (w->state == WALL_DOOR_CLOSED)) //closed
759 if (!is_door_free(seg,side))
762 if (w->state == WALL_DOOR_OPENING) { //reuse door
768 for (i=0;i<Num_open_doors;i++) { //find door
772 if (d->front_wallnum[0]==wall_num || d->back_wallnum[0]==wall_num ||
773 (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num)))
777 Assert(i<Num_open_doors); //didn't find door!
778 Assert( d!=NULL ); // Get John!
780 d->time = WallAnims[w->clip_num].play_time - d->time;
786 else { //create new door
787 Assert(w->state == WALL_DOOR_OPEN);
788 d = &ActiveDoors[Num_open_doors];
791 Assert( Num_open_doors < MAX_DOORS );
794 w->state = WALL_DOOR_CLOSING;
796 // So that door can't be shot while opening
797 csegp = &Segments[seg->children[side]];
798 Connectside = find_connect_side(seg, csegp);
799 Assert(Connectside != -1);
800 cwall_num = csegp->sides[Connectside].wall_num;
802 Walls[cwall_num].state = WALL_DOOR_CLOSING;
804 d->front_wallnum[0] = seg->sides[side].wall_num;
805 d->back_wallnum[0] = cwall_num;
807 Assert( seg-Segments != -1);
809 if (Newdemo_state == ND_STATE_RECORDING) {
810 newdemo_record_door_opening(seg-Segments, side);
813 if (w->linked_wall != -1) {
814 Int3(); //don't think we ever used linked walls
820 if ( Newdemo_state != ND_STATE_PLAYBACK )
822 // NOTE THE LINK TO ABOVE!!!!
824 compute_center_point_on_side(&cp, seg, side );
825 if (WallAnims[w->clip_num].open_sound > -1 )
826 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
831 //-----------------------------------------------------------------
832 // Animates opening of a door.
833 // Called in the game loop.
834 void do_door_open(int door_num)
839 Assert(door_num != -1); //Trying to do_door_open on illegal door
841 d = &ActiveDoors[door_num];
843 for (p=0;p<d->n_parts;p++) {
845 int Connectside, side;
846 segment *csegp, *seg;
847 fix time_elapsed, time_total, one_frame;
850 w = &Walls[d->front_wallnum[p]];
851 kill_stuck_objects(d->front_wallnum[p]);
852 kill_stuck_objects(d->back_wallnum[p]);
854 seg = &Segments[w->segnum];
857 Assert(seg->sides[side].wall_num != -1); //Trying to do_door_open on illegal wall
859 csegp = &Segments[seg->children[side]];
860 Connectside = find_connect_side(seg, csegp);
861 Assert(Connectside != -1);
863 d->time += FrameTime;
865 time_elapsed = d->time;
866 n = WallAnims[w->clip_num].num_frames;
867 time_total = WallAnims[w->clip_num].play_time;
869 one_frame = time_total/n;
871 i = time_elapsed/one_frame;
874 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
877 Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED;
878 Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED;
882 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1);
884 // If our door is not automatic just remove it from the list.
885 if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) {
886 for (i=door_num;i<Num_open_doors;i++)
887 ActiveDoors[i] = ActiveDoors[i+1];
889 Walls[seg->sides[side].wall_num].state = WALL_DOOR_OPEN;
890 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPEN;
894 Walls[seg->sides[side].wall_num].state = WALL_DOOR_WAITING;
895 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING;
897 ActiveDoors[Num_open_doors].time = 0; //counts up
905 //-----------------------------------------------------------------
906 // Animates and processes the closing of a door.
907 // Called from the game loop.
908 void do_door_close(int door_num)
914 Assert(door_num != -1); //Trying to do_door_open on illegal door
916 d = &ActiveDoors[door_num];
918 w = &Walls[d->front_wallnum[0]];
920 //check for objects in doorway before closing
921 if (w->flags & WALL_DOOR_AUTO)
922 if (!is_door_free(&Segments[w->segnum],w->sidenum)) {
923 digi_kill_sound_linked_to_segment(w->segnum,w->sidenum,-1);
924 wall_open_door(&Segments[w->segnum],w->sidenum); //re-open door
928 for (p=0;p<d->n_parts;p++) {
930 int Connectside, side;
931 segment *csegp, *seg;
932 fix time_elapsed, time_total, one_frame;
935 w = &Walls[d->front_wallnum[p]];
937 seg = &Segments[w->segnum];
940 if (seg->sides[side].wall_num == -1) {
941 mprintf((0, "Trying to do_door_close on Illegal wall\n"));
945 //if here, must be auto door
946 // Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO);
947 //don't assert here, because now we have triggers to close non-auto doors
949 // Otherwise, close it.
950 csegp = &Segments[seg->children[side]];
951 Connectside = find_connect_side(seg, csegp);
952 Assert(Connectside != -1);
955 if ( Newdemo_state != ND_STATE_PLAYBACK )
956 // NOTE THE LINK TO ABOVE!!
957 if (p==0) //only play one sound for linked doors
958 if ( d->time==0 ) { //first time
960 compute_center_point_on_side(&cp, seg, side );
961 if (WallAnims[w->clip_num].close_sound > -1 )
962 digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, seg-Segments, side, &cp, 0, F1_0 );
965 d->time += FrameTime;
967 time_elapsed = d->time;
968 n = WallAnims[w->clip_num].num_frames;
969 time_total = WallAnims[w->clip_num].play_time;
971 one_frame = time_total/n;
973 i = n-time_elapsed/one_frame-1;
976 Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED;
977 Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED;
982 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
984 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING;
985 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
987 ActiveDoors[Num_open_doors].time = 0; //counts up
990 wall_close_door_num(door_num);
995 //-----------------------------------------------------------------
996 // Turns off an illusionary wall (This will be used primarily for
997 // wall switches or triggers that can turn on/off illusionary walls.)
998 void wall_illusion_off(segment *seg, int side)
1003 csegp = &Segments[seg->children[side]];
1004 cside = find_connect_side(seg, csegp);
1005 Assert(cside != -1);
1007 if (seg->sides[side].wall_num == -1) {
1008 mprintf((0, "Trying to shut off illusion illegal wall\n"));
1012 Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF;
1013 Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF;
1015 kill_stuck_objects(seg->sides[side].wall_num);
1016 kill_stuck_objects(csegp->sides[cside].wall_num);
1019 //-----------------------------------------------------------------
1020 // Turns on an illusionary wall (This will be used primarily for
1021 // wall switches or triggers that can turn on/off illusionary walls.)
1022 void wall_illusion_on(segment *seg, int side)
1027 csegp = &Segments[seg->children[side]];
1028 cside = find_connect_side(seg, csegp);
1029 Assert(cside != -1);
1031 if (seg->sides[side].wall_num == -1) {
1032 mprintf((0, "Trying to turn on illusion illegal wall\n"));
1036 Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF;
1037 Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF;
1040 // -----------------------------------------------------------------------------
1041 // Allowed to open the normally locked special boss door if in multiplayer mode.
1042 int special_boss_opening_allowed(int segnum, int sidenum)
1044 if (Game_mode & GM_MULTI)
1045 return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE);
1050 //-----------------------------------------------------------------
1051 // Determines what happens when a wall is shot
1052 //returns info about wall. see wall.h for codes
1053 //obj is the object that hit...either a weapon or the player himself
1054 //playernum is the number the player who hit the wall or fired the weapon,
1055 //or -1 if a robot fired the weapon
1056 int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj )
1061 Assert (seg-Segments != -1);
1063 // If it is not a "wall" then just return.
1064 if ( seg->sides[side].wall_num < 0 )
1065 return WHP_NOT_SPECIAL;
1067 w = &Walls[seg->sides[side].wall_num];
1069 if ( Newdemo_state == ND_STATE_RECORDING )
1070 newdemo_record_wall_hit_process( seg-Segments, side, damage, playernum );
1072 if (w->type == WALL_BLASTABLE) {
1073 if (obj->ctype.laser_info.parent_type == OBJ_PLAYER)
1074 wall_damage(seg, side, damage);
1075 return WHP_BLASTABLE;
1078 if (playernum != Player_num) //return if was robot fire
1079 return WHP_NOT_SPECIAL;
1081 Assert( playernum > -1 );
1083 // Determine whether player is moving forward. If not, don't say negative
1084 // messages because he probably didn't intentionally hit the door.
1085 if (obj->type == OBJ_PLAYER)
1086 show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0);
1087 else if (obj->type == OBJ_ROBOT)
1089 else if ((obj->type == OBJ_WEAPON) && (obj->ctype.laser_info.parent_type == OBJ_ROBOT))
1094 if (w->keys == KEY_BLUE)
1095 if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) {
1096 if ( playernum==Player_num )
1098 HUD_init_message("%s %s",TXT_BLUE,TXT_ACCESS_DENIED);
1102 if (w->keys == KEY_RED)
1103 if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) {
1104 if ( playernum==Player_num )
1106 HUD_init_message("%s %s",TXT_RED,TXT_ACCESS_DENIED);
1110 if (w->keys == KEY_GOLD)
1111 if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) {
1112 if ( playernum==Player_num )
1114 HUD_init_message("%s %s",TXT_YELLOW,TXT_ACCESS_DENIED);
1118 if (w->type == WALL_DOOR)
1120 if ((w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(seg-Segments, side)) ) {
1121 if ( playernum==Player_num )
1123 HUD_init_message(TXT_CANT_OPEN_DOOR);
1127 if (w->state != WALL_DOOR_OPENING)
1129 wall_open_door(seg, side);
1131 if (Game_mode & GM_MULTI)
1132 multi_send_door_open(seg-Segments, side,w->flags);
1140 return WHP_NOT_SPECIAL; //default is treat like normal wall
1143 //-----------------------------------------------------------------
1144 // Opens doors/destroys wall/shuts off triggers.
1145 void wall_toggle(segment *seg, int side)
1149 if (seg - Segments > Highest_segment_index)
1151 Warning("Can't toggle side %d of segment %d - nonexistent segment!\n", side, seg-Segments);
1154 Assert( side < MAX_SIDES_PER_SEGMENT );
1156 wall_num = seg->sides[side].wall_num;
1158 if (wall_num == -1) {
1159 mprintf((0, "Illegal wall_toggle\n"));
1163 if ( Newdemo_state == ND_STATE_RECORDING )
1164 newdemo_record_wall_toggle(seg-Segments, side );
1166 if (Walls[wall_num].type == WALL_BLASTABLE)
1167 wall_destroy(seg, side);
1169 if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED))
1170 wall_open_door(seg, side);
1175 //-----------------------------------------------------------------
1176 // Tidy up Walls array for load/save purposes.
1181 if (Num_walls < 0) {
1182 mprintf((0, "Illegal Num_walls\n"));
1186 for (i=Num_walls;i<MAX_WALLS;i++) {
1187 Walls[i].type = WALL_NORMAL;
1190 Walls[i].trigger = -1;
1191 Walls[i].clip_num = -1;
1195 void do_cloaking_wall_frame(int cloaking_wall_num)
1198 wall *wfront,*wback;
1200 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1202 d = &CloakingWalls[cloaking_wall_num];
1203 wfront = &Walls[d->front_wallnum];
1204 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1206 d->time += FrameTime;
1208 if (d->time > CLOAKING_WALL_TIME) {
1211 wfront->type = WALL_OPEN;
1212 wfront->state = WALL_DOOR_CLOSED; //why closed? why not?
1214 wback->type = WALL_OPEN;
1215 wback->state = WALL_DOOR_CLOSED; //why closed? why not?
1218 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1219 CloakingWalls[i] = CloakingWalls[i+1];
1220 Num_cloaking_walls--;
1223 else if (d->time > CLOAKING_WALL_TIME/2) {
1224 int old_type=wfront->type;
1226 wfront->cloak_value = ((d->time - CLOAKING_WALL_TIME/2) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1228 wback->cloak_value = wfront->cloak_value;
1230 if (old_type != WALL_CLOAKED) { //just switched
1233 wfront->type = WALL_CLOAKED;
1235 wback->type = WALL_CLOAKED;
1238 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1240 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1248 light_scale = fixdiv(CLOAKING_WALL_TIME/2-d->time,CLOAKING_WALL_TIME/2);
1251 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1253 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1257 if ( Newdemo_state == ND_STATE_RECORDING )
1258 newdemo_record_cloaking_wall(d->front_wallnum, d->back_wallnum, wfront->type, wfront->state, wfront->cloak_value, Segments[wfront->segnum].sides[wfront->sidenum].uvls[0].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[1].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[2].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[3].l);
1262 void do_decloaking_wall_frame(int cloaking_wall_num)
1265 wall *wfront,*wback;
1267 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1269 d = &CloakingWalls[cloaking_wall_num];
1270 wfront = &Walls[d->front_wallnum];
1271 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1273 d->time += FrameTime;
1275 if (d->time > CLOAKING_WALL_TIME) {
1278 wfront->state = WALL_DOOR_CLOSED;
1280 wback->state = WALL_DOOR_CLOSED;
1283 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1285 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1288 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1289 CloakingWalls[i] = CloakingWalls[i+1];
1290 Num_cloaking_walls--;
1293 else if (d->time > CLOAKING_WALL_TIME/2) { //fading in
1297 wfront->type = wback->type = WALL_CLOSED;
1299 light_scale = fixdiv(d->time-CLOAKING_WALL_TIME/2,CLOAKING_WALL_TIME/2);
1302 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1304 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1307 else { //cloaking in
1308 wfront->cloak_value = ((CLOAKING_WALL_TIME/2 - d->time) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1309 wfront->type = WALL_CLOAKED;
1311 wback->cloak_value = wfront->cloak_value;
1312 wback->type = WALL_CLOAKED;
1316 if ( Newdemo_state == ND_STATE_RECORDING )
1317 newdemo_record_cloaking_wall(d->front_wallnum, d->back_wallnum, wfront->type, wfront->state, wfront->cloak_value, Segments[wfront->segnum].sides[wfront->sidenum].uvls[0].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[1].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[2].l, Segments[wfront->segnum].sides[wfront->sidenum].uvls[3].l);
1321 void wall_frame_process()
1325 for (i=0;i<Num_open_doors;i++) {
1329 d = &ActiveDoors[i];
1330 w = &Walls[d->front_wallnum[0]];
1332 if (w->state == WALL_DOOR_OPENING)
1334 else if (w->state == WALL_DOOR_CLOSING)
1336 else if (w->state == WALL_DOOR_WAITING) {
1337 d->time += FrameTime;
1339 //set flags to fix occatsional netgame problem where door is
1340 //waiting to close but open flag isn't set
1341 Assert(d->n_parts == 1);
1342 w->flags |= WALL_DOOR_OPENED;
1343 if (d->back_wallnum[0] > -1)
1344 Walls[d->back_wallnum[0]].flags |= WALL_DOOR_OPENED;
1346 if (d->time > DOOR_WAIT_TIME && is_door_free(&Segments[w->segnum],w->sidenum)) {
1347 w->state = WALL_DOOR_CLOSING;
1351 else if (w->state == WALL_DOOR_CLOSED || w->state == WALL_DOOR_OPEN) {
1352 //this shouldn't happen. if the wall is in one of these states,
1353 //there shouldn't be an activedoor entry for it. So we'll kill
1354 //the activedoor entry. Tres simple.
1356 Int3(); //a bad thing has happened, but I'll try to fix it up
1357 for (t=i;t<Num_open_doors;t++)
1358 ActiveDoors[t] = ActiveDoors[t+1];
1363 for (i=0;i<Num_cloaking_walls;i++) {
1367 d = &CloakingWalls[i];
1368 w = &Walls[d->front_wallnum];
1370 if (w->state == WALL_DOOR_CLOAKING)
1371 do_cloaking_wall_frame(i);
1372 else if (w->state == WALL_DOOR_DECLOAKING)
1373 do_decloaking_wall_frame(i);
1376 Int3(); //unexpected wall state
1381 int Num_stuck_objects=0;
1383 stuckobj Stuck_objects[MAX_STUCK_OBJECTS];
1385 // An object got stuck in a door (like a flare).
1386 // Add global entry.
1387 void add_stuck_object(object *objp, int segnum, int sidenum)
1392 wallnum = Segments[segnum].sides[sidenum].wall_num;
1394 if (wallnum != -1) {
1395 if (Walls[wallnum].flags & WALL_BLASTED)
1396 objp->flags |= OF_SHOULD_BE_DEAD;
1398 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1399 if (Stuck_objects[i].wallnum == -1) {
1400 Stuck_objects[i].wallnum = wallnum;
1401 Stuck_objects[i].objnum = objp-Objects;
1402 Stuck_objects[i].signature = objp->signature;
1403 // mprintf((0, "Added wall %i at index %i\n", wallnum, i));
1404 Num_stuck_objects++;
1408 if (i == MAX_STUCK_OBJECTS)
1409 mprintf((1, "Warning: Unable to add object %i which got stuck in wall %i to Stuck_objects\n", objp-Objects, wallnum));
1416 // --------------------------------------------------------------------------------------------------
1417 // Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here.
1418 // Removes up to one/frame.
1419 void remove_obsolete_stuck_objects(void)
1423 // Safety and efficiency code. If no stuck objects, should never get inside the IF, but this is faster.
1424 if (!Num_stuck_objects)
1427 objnum = FrameCount % MAX_STUCK_OBJECTS;
1429 if (Stuck_objects[objnum].wallnum != -1)
1430 if ((Walls[Stuck_objects[objnum].wallnum].state != WALL_DOOR_CLOSED) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) {
1431 Num_stuck_objects--;
1432 Objects[Stuck_objects[objnum].objnum].lifeleft = F1_0/8;
1433 Stuck_objects[objnum].wallnum = -1;
1438 extern void flush_fcd_cache(void);
1440 // ----------------------------------------------------------------------------------------------------
1441 // Door with wall index wallnum is opening, kill all objects stuck in it.
1442 void kill_stuck_objects(int wallnum)
1446 if (wallnum < 0 || Num_stuck_objects == 0) {
1450 Num_stuck_objects=0;
1452 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1453 if (Stuck_objects[i].wallnum == wallnum) {
1454 if (Objects[Stuck_objects[i].objnum].type == OBJ_WEAPON) {
1455 Objects[Stuck_objects[i].objnum].lifeleft = F1_0/8;
1457 mprintf((1, "Warning: Stuck object of type %i, expected to be of type %i, see wall.c\n", Objects[Stuck_objects[i].objnum].type, OBJ_WEAPON));
1458 // Int3(); // What? This looks bad. Object is not a weapon and it is stuck in a wall!
1459 Stuck_objects[i].wallnum = -1;
1460 } else if (Stuck_objects[i].wallnum != -1) {
1461 Num_stuck_objects++;
1463 // Ok, this is awful, but we need to do things whenever a door opens/closes/disappears, etc.
1469 // -- unused -- // -----------------------------------------------------------------------------------
1470 // -- unused -- // Return object id of first flare found embedded in segp:sidenum.
1471 // -- unused -- // If no flare, return -1.
1472 // -- unused -- int contains_flare(segment *segp, int sidenum)
1474 // -- unused -- int i;
1476 // -- unused -- for (i=0; i<Num_stuck_objects; i++) {
1477 // -- unused -- object *objp = &Objects[Stuck_objects[i].objnum];
1479 // -- unused -- if ((objp->type == OBJ_WEAPON) && (objp->id == FLARE_ID)) {
1480 // -- unused -- if (Walls[Stuck_objects[i].wallnum].segnum == segp-Segments)
1481 // -- unused -- if (Walls[Stuck_objects[i].wallnum].sidenum == sidenum)
1482 // -- unused -- return objp-Objects;
1486 // -- unused -- return -1;
1489 // -----------------------------------------------------------------------------------
1490 // Initialize stuck objects array. Called at start of level
1491 void init_stuck_objects(void)
1495 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1496 Stuck_objects[i].wallnum = -1;
1498 Num_stuck_objects = 0;
1501 // -----------------------------------------------------------------------------------
1502 // Clear out all stuck objects. Called for a new ship
1503 void clear_stuck_objects(void)
1507 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1508 if (Stuck_objects[i].wallnum != -1) {
1511 objnum = Stuck_objects[i].objnum;
1513 if ((Objects[objnum].type == OBJ_WEAPON) && (Objects[objnum].id == FLARE_ID))
1514 Objects[objnum].lifeleft = F1_0/8;
1516 Stuck_objects[i].wallnum = -1;
1518 Num_stuck_objects--;
1522 Assert(Num_stuck_objects == 0);
1526 // -----------------------------------------------------------------------------------
1527 #define MAX_BLAST_GLASS_DEPTH 5
1529 void bng_process_segment(object *objp, fix damage, segment *segp, int depth, sbyte *visited)
1533 if (depth > MAX_BLAST_GLASS_DEPTH)
1538 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1543 // Process only walls which have glass.
1544 if ((tm=segp->sides[sidenum].tmap_num2) != 0) {
1547 tm &= 0x3fff; //tm without flags
1549 if ((((ec=TmapInfo[tm].eclip_num)!=-1) && ((db=Effects[ec].dest_bm_num)!=-1 && !(Effects[ec].flags&EF_ONE_SHOT))) || (ec==-1 && (TmapInfo[tm].destroyed!=-1))) {
1550 compute_center_point_on_side(&pnt, segp, sidenum);
1551 dist = vm_vec_dist_quick(&pnt, &objp->pos);
1552 if (dist < damage/2) {
1553 dist = find_connected_distance(&pnt, segp-Segments, &objp->pos, objp->segnum, MAX_BLAST_GLASS_DEPTH, WID_RENDPAST_FLAG);
1554 if ((dist > 0) && (dist < damage/2))
1555 check_effect_blowup(segp, sidenum, &pnt, &Objects[objp->ctype.laser_info.parent_num], 1);
1561 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1562 int segnum = segp->children[i];
1565 if (!visited[segnum]) {
1566 if (WALL_IS_DOORWAY(segp, i) & WID_FLY_FLAG) {
1567 visited[segnum] = 1;
1568 bng_process_segment(objp, damage, &Segments[segnum], depth, visited);
1575 // -----------------------------------------------------------------------------------
1576 // objp is going to detonate
1577 // blast nearby monitors, lights, maybe other things
1578 void blast_nearby_glass(object *objp, fix damage)
1581 sbyte visited[MAX_SEGMENTS];
1584 cursegp = &Segments[objp->segnum];
1585 for (i=0; i<=Highest_segment_index; i++)
1588 visited[objp->segnum] = 1;
1589 bng_process_segment(objp, damage, cursegp, 0, visited);
1594 #define MAX_CLIP_FRAMES_D1 20
1597 * reads a wclip structure from a CFILE
1599 int wclip_read_n_d1(wclip *wc, int n, CFILE *fp)
1603 for (i = 0; i < n; i++) {
1604 wc[i].play_time = cfile_read_fix(fp);
1605 wc[i].num_frames = cfile_read_short(fp);
1606 for (j = 0; j < MAX_CLIP_FRAMES_D1; j++)
1607 wc[i].frames[j] = cfile_read_short(fp);
1608 wc[i].open_sound = cfile_read_short(fp);
1609 wc[i].close_sound = cfile_read_short(fp);
1610 wc[i].flags = cfile_read_short(fp);
1611 cfread(wc[i].filename, 13, 1, fp);
1612 wc[i].pad = cfile_read_byte(fp);
1617 #ifndef FAST_FILE_IO
1619 * reads a wclip structure from a CFILE
1621 int wclip_read_n(wclip *wc, int n, CFILE *fp)
1625 for (i = 0; i < n; i++) {
1626 wc[i].play_time = cfile_read_fix(fp);
1627 wc[i].num_frames = cfile_read_short(fp);
1628 for (j = 0; j < MAX_CLIP_FRAMES; j++)
1629 wc[i].frames[j] = cfile_read_short(fp);
1630 wc[i].open_sound = cfile_read_short(fp);
1631 wc[i].close_sound = cfile_read_short(fp);
1632 wc[i].flags = cfile_read_short(fp);
1633 cfread(wc[i].filename, 13, 1, fp);
1634 wc[i].pad = cfile_read_byte(fp);
1640 * reads a v16_wall structure from a CFILE
1642 extern void v16_wall_read(v16_wall *w, CFILE *fp)
1644 w->type = cfile_read_byte(fp);
1645 w->flags = cfile_read_byte(fp);
1646 w->hps = cfile_read_fix(fp);
1647 w->trigger = cfile_read_byte(fp);
1648 w->clip_num = cfile_read_byte(fp);
1649 w->keys = cfile_read_byte(fp);
1653 * reads a v19_wall structure from a CFILE
1655 extern void v19_wall_read(v19_wall *w, CFILE *fp)
1657 w->segnum = cfile_read_int(fp);
1658 w->sidenum = cfile_read_int(fp);
1659 w->type = cfile_read_byte(fp);
1660 w->flags = cfile_read_byte(fp);
1661 w->hps = cfile_read_fix(fp);
1662 w->trigger = cfile_read_byte(fp);
1663 w->clip_num = cfile_read_byte(fp);
1664 w->keys = cfile_read_byte(fp);
1665 w->linked_wall = cfile_read_int(fp);
1669 * reads a wall structure from a CFILE
1671 extern void wall_read(wall *w, CFILE *fp)
1673 w->segnum = cfile_read_int(fp);
1674 w->sidenum = cfile_read_int(fp);
1675 w->hps = cfile_read_fix(fp);
1676 w->linked_wall = cfile_read_int(fp);
1677 w->type = cfile_read_byte(fp);
1678 w->flags = cfile_read_byte(fp);
1679 w->state = cfile_read_byte(fp);
1680 w->trigger = cfile_read_byte(fp);
1681 w->clip_num = cfile_read_byte(fp);
1682 w->keys = cfile_read_byte(fp);
1683 w->controlling_trigger = cfile_read_byte(fp);
1684 w->cloak_value = cfile_read_byte(fp);
1688 * reads a v19_door structure from a CFILE
1690 extern void v19_door_read(v19_door *d, CFILE *fp)
1692 d->n_parts = cfile_read_int(fp);
1693 d->seg[0] = cfile_read_short(fp);
1694 d->seg[1] = cfile_read_short(fp);
1695 d->side[0] = cfile_read_short(fp);
1696 d->side[1] = cfile_read_short(fp);
1697 d->type[0] = cfile_read_short(fp);
1698 d->type[1] = cfile_read_short(fp);
1699 d->open = cfile_read_fix(fp);
1703 * reads an active_door structure from a CFILE
1705 extern void active_door_read(active_door *ad, CFILE *fp)
1707 ad->n_parts = cfile_read_int(fp);
1708 ad->front_wallnum[0] = cfile_read_short(fp);
1709 ad->front_wallnum[1] = cfile_read_short(fp);
1710 ad->back_wallnum[0] = cfile_read_short(fp);
1711 ad->back_wallnum[1] = cfile_read_short(fp);
1712 ad->time = cfile_read_fix(fp);