1 /* $Id: wall.c,v 1.9 2003-04-03 07:12:46 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.
20 static char rcsid[] = "$Id: wall.c,v 1.9 2003-04-03 07:12:46 btb Exp $";
49 #include "laser.h" // For seeing if a flare is stuck in a wall.
54 #include "editor/editor.h"
57 // Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK.
58 #define BOSS_LOCKED_DOOR_LEVEL 7
59 #define BOSS_LOCKED_DOOR_SEG 595
60 #define BOSS_LOCKED_DOOR_SIDE 5
62 wall Walls[MAX_WALLS]; // Master walls array
63 int Num_walls=0; // Number of walls
65 wclip WallAnims[MAX_WALL_ANIMS]; // Wall animations
67 //--unused-- int walls_bm_num[MAX_WALL_ANIMS];
69 //door Doors[MAX_DOORS]; // Master doors array
71 active_door ActiveDoors[MAX_DOORS];
72 int Num_open_doors; // Number of open doors
74 #define CLOAKING_WALL_TIME f1_0
76 #define MAX_CLOAKING_WALLS 10
77 cloaking_wall CloakingWalls[MAX_CLOAKING_WALLS];
78 int Num_cloaking_walls;
80 //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS];
82 //#define BM_FLAG_TRANSPARENT 1
83 //#define BM_FLAG_SUPER_TRANSPARENT 2
86 char Wall_names[7][10] = {
97 // Function prototypes
98 void kill_stuck_objects(int wallnum);
102 // This function determines whether the current segment/side is transparent
105 int check_transparency( segment * seg, int side )
107 if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) {
108 if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT )
114 if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT )
120 //define these here so I don't have to change wall_is_doorway and run
121 //the risk of screwing it up.
122 #define WID_WALL 2 // 0/1/0 wall
123 #define WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
124 #define WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
125 #define WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
126 #define WID_NO_WALL 5 // 1/0/1 no wall, can fly through
127 #define WID_EXTERNAL 8 // 0/0/0/1 don't see it, dont fly through it
129 //-----------------------------------------------------------------
130 // This function checks whether we can fly through the given side.
131 // In other words, whether or not we have a 'doorway'
135 // WID_RENDPAST_FLAG 4
137 // WID_WALL 2 // 0/1/0 wall
138 // WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
139 // WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
140 // WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
141 // WID_NO_WALL 5 // 1/0/1 no wall, can fly through
142 int wall_is_doorway ( segment * seg, int side )
146 //--Covered by macro // No child.
147 //--Covered by macro if (seg->children[side] == -1)
148 //--Covered by macro return WID_WALL;
150 //--Covered by macro if (seg->children[side] == -2)
151 //--Covered by macro return WID_EXTERNAL_FLAG;
153 //--Covered by macro // No wall present.
154 //--Covered by macro if (seg->sides[side].wall_num == -1)
155 //--Covered by macro return WID_NO_WALL;
157 Assert(seg-Segments>=0 && seg-Segments<=Highest_segment_index);
158 Assert(side>=0 && side<6);
160 type = Walls[seg->sides[side].wall_num].type;
161 flags = Walls[seg->sides[side].wall_num].flags;
163 if (type == WALL_OPEN)
166 if (type == WALL_ILLUSION) {
167 if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF)
170 if (check_transparency( seg, side))
171 return WID_TRANSILLUSORY_WALL;
173 return WID_ILLUSORY_WALL;
177 if (type == WALL_BLASTABLE) {
178 if (flags & WALL_BLASTED)
179 return WID_TRANSILLUSORY_WALL;
181 if (check_transparency( seg, side))
182 return WID_TRANSPARENT_WALL;
187 if (flags & WALL_DOOR_OPENED)
188 return WID_TRANSILLUSORY_WALL;
190 if (type == WALL_CLOAKED)
191 return WID_RENDER_FLAG | WID_RENDPAST_FLAG | WID_CLOAKED_FLAG;
193 state = Walls[seg->sides[side].wall_num].state;
194 if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING))
195 return WID_TRANSPARENT_WALL;
197 // If none of the above flags are set, there is no doorway.
198 if (check_transparency( seg, side))
199 return WID_TRANSPARENT_WALL;
201 return WID_WALL; // There are children behind the door.
205 //-----------------------------------------------------------------
206 // Initializes all the walls (in other words, no special walls)
212 for (i=0;i<MAX_WALLS;i++) {
213 Walls[i].segnum = Walls[i].sidenum = -1;
214 Walls[i].type = WALL_NORMAL;
217 Walls[i].trigger = -1;
218 Walls[i].clip_num = -1;
219 Walls[i].linked_wall = -1;
222 Num_cloaking_walls = 0;
226 //-----------------------------------------------------------------
227 // Initializes one wall.
228 void wall_reset(segment *seg, int side)
232 i = seg->sides[side].wall_num;
235 mprintf((0, "Resetting Illegal Wall\n"));
239 Walls[i].segnum = seg-Segments;
240 Walls[i].sidenum = side;
241 Walls[i].type = WALL_NORMAL;
244 Walls[i].trigger = -1;
245 Walls[i].clip_num = -1;
246 Walls[i].linked_wall = -1;
250 //set the tmap_num or tmap_num2 field for a wall/door
251 void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num)
253 wclip *anim = &WallAnims[anim_num];
254 int tmap = anim->frames[frame_num];
256 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
258 if (anim->flags & WCF_TMAP1) {
259 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap;
260 if ( Newdemo_state == ND_STATE_RECORDING )
261 newdemo_record_wall_set_tmap_num1(seg-Segments,side,csegp-Segments,cside,tmap);
263 Assert(tmap!=0 && seg->sides[side].tmap_num2!=0);
264 seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap;
265 if ( Newdemo_state == ND_STATE_RECORDING )
266 newdemo_record_wall_set_tmap_num2(seg-Segments,side,csegp-Segments,cside,tmap);
271 // -------------------------------------------------------------------------------
272 //when the wall has used all its hitpoints, this will destroy it
273 void blast_blastable_wall(segment *seg, int side)
279 Assert(seg->sides[side].wall_num != -1);
281 Walls[seg->sides[side].wall_num].hps = -1; //say it's blasted
283 csegp = &Segments[seg->children[side]];
284 Connectside = find_connect_side(seg, csegp);
285 Assert(Connectside != -1);
287 kill_stuck_objects(seg->sides[side].wall_num);
288 kill_stuck_objects(csegp->sides[Connectside].wall_num);
290 //if this is an exploding wall, explode it
291 if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES)
292 explode_wall(seg-Segments,side);
294 //if not exploding, set final frame, and make door passable
295 a = Walls[seg->sides[side].wall_num].clip_num;
296 n = WallAnims[a].num_frames;
297 wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1);
298 Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED;
299 Walls[csegp->sides[Connectside].wall_num].flags |= WALL_BLASTED;
305 //-----------------------------------------------------------------
306 // Destroys a blastable wall.
307 void wall_destroy(segment *seg, int side)
309 Assert(seg->sides[side].wall_num != -1);
310 Assert(seg-Segments != 0);
312 if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
313 blast_blastable_wall( seg, side );
315 Error("Hey bub, you are trying to destroy an indestructable wall.");
318 //-----------------------------------------------------------------
319 // Deteriorate appearance of wall. (Changes bitmap (paste-ons))
320 void wall_damage(segment *seg, int side, fix damage)
324 if (seg->sides[side].wall_num == -1) {
325 mprintf((0, "Damaging illegal wall\n"));
329 if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE)
332 if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED) && Walls[seg->sides[side].wall_num].hps >= 0)
337 csegp = &Segments[seg->children[side]];
338 Connectside = find_connect_side(seg, csegp);
339 Assert(Connectside != -1);
341 Walls[seg->sides[side].wall_num].hps -= damage;
342 Walls[csegp->sides[Connectside].wall_num].hps -= damage;
344 a = Walls[seg->sides[side].wall_num].clip_num;
345 n = WallAnims[a].num_frames;
347 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) {
348 blast_blastable_wall( seg, side );
350 if (Game_mode & GM_MULTI)
351 multi_send_door_open(seg-Segments, side,Walls[seg->sides[side].wall_num].flags);
356 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*(n-i)/n) {
357 wall_set_tmap_num(seg,side,csegp,Connectside,a,i);
363 //-----------------------------------------------------------------
365 void wall_open_door(segment *seg, int side)
372 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
374 w = &Walls[seg->sides[side].wall_num];
376 //kill_stuck_objects(seg->sides[side].wall_num);
378 if ((w->state == WALL_DOOR_OPENING) || //already opening
379 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
380 (w->state == WALL_DOOR_OPEN)) //open, & staying open
383 if (w->state == WALL_DOOR_CLOSING) { //closing, so reuse door
389 for (i=0;i<Num_open_doors;i++) { //find door
393 if (d->front_wallnum[0]==w-Walls || d->back_wallnum[0]==w-Walls || (d->n_parts==2 && (d->front_wallnum[1]==w-Walls || d->back_wallnum[1]==w-Walls)))
397 if (i>=Num_open_doors && (Game_mode & GM_MULTI))
400 Assert(i<Num_open_doors); //didn't find door!
401 Assert( d!=NULL ); // Get John!
403 d->time = WallAnims[w->clip_num].play_time - d->time;
409 else { //create new door
410 Assert(w->state == WALL_DOOR_CLOSED);
412 d = &ActiveDoors[Num_open_doors];
415 Assert( Num_open_doors < MAX_DOORS );
419 w->state = WALL_DOOR_OPENING;
421 // So that door can't be shot while opening
422 csegp = &Segments[seg->children[side]];
423 Connectside = find_connect_side(seg, csegp);
424 Assert(Connectside != -1);
426 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPENING;
428 //kill_stuck_objects(csegp->sides[Connectside].wall_num);
430 d->front_wallnum[0] = seg->sides[side].wall_num;
431 d->back_wallnum[0] = csegp->sides[Connectside].wall_num;
433 Assert( seg-Segments != -1);
435 if (Newdemo_state == ND_STATE_RECORDING) {
436 newdemo_record_door_opening(seg-Segments, side);
439 if (w->linked_wall != -1) {
443 w2 = &Walls[w->linked_wall];
444 seg2 = &Segments[w2->segnum];
446 Assert(w2->linked_wall == seg->sides[side].wall_num);
447 //Assert(!(w2->flags & WALL_DOOR_OPENING || w2->flags & WALL_DOOR_OPENED));
449 w2->state = WALL_DOOR_OPENING;
451 csegp = &Segments[seg2->children[w2->sidenum]];
452 Connectside = find_connect_side(seg2, csegp);
453 Assert(Connectside != -1);
454 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPENING;
457 d->front_wallnum[1] = w->linked_wall;
458 d->back_wallnum[1] = csegp->sides[Connectside].wall_num;
464 if ( Newdemo_state != ND_STATE_PLAYBACK )
466 // NOTE THE LINK TO ABOVE!!!!
468 compute_center_point_on_side(&cp, seg, side );
469 if (WallAnims[w->clip_num].open_sound > -1 )
470 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
475 //-----------------------------------------------------------------
476 // start the transition from closed -> open wall
477 void start_wall_cloak(segment *seg, int side)
485 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
487 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
489 w = &Walls[seg->sides[side].wall_num];
491 if (w->type == WALL_OPEN || w->state == WALL_DOOR_CLOAKING) //already open or cloaking
494 csegp = &Segments[seg->children[side]];
495 Connectside = find_connect_side(seg, csegp);
496 Assert(Connectside != -1);
498 if (w->state == WALL_DOOR_DECLOAKING) { //decloaking, so reuse door
504 for (i=0;i<Num_cloaking_walls;i++) { //find door
506 d = &CloakingWalls[i];
508 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
512 Assert(i<Num_cloaking_walls); //didn't find door!
513 Assert( d!=NULL ); // Get John!
515 d->time = CLOAKING_WALL_TIME - d->time;
518 else if (w->state == WALL_DOOR_CLOSED) { //create new door
519 d = &CloakingWalls[Num_cloaking_walls];
521 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
522 Int3(); //ran out of cloaking wall slots
524 Walls[csegp->sides[Connectside].wall_num].type = WALL_OPEN;
527 Num_cloaking_walls++;
530 Int3(); //unexpected wall state
534 w->state = WALL_DOOR_CLOAKING;
535 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOAKING;
537 d->front_wallnum = seg->sides[side].wall_num;
538 d->back_wallnum = csegp->sides[Connectside].wall_num;
540 Assert( seg-Segments != -1);
542 Assert(w->linked_wall == -1);
544 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
546 compute_center_point_on_side(&cp, seg, side );
547 digi_link_sound_to_pos( SOUND_WALL_CLOAK_ON, seg-Segments, side, &cp, 0, F1_0 );
551 d->front_ls[i] = seg->sides[side].uvls[i].l;
552 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
556 //-----------------------------------------------------------------
557 // start the transition from open -> closed wall
558 void start_wall_decloak(segment *seg, int side)
566 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
568 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
570 w = &Walls[seg->sides[side].wall_num];
572 if (w->type == WALL_CLOSED || w->state == WALL_DOOR_DECLOAKING) //already closed or decloaking
575 if (w->state == WALL_DOOR_CLOAKING) { //cloaking, so reuse door
581 for (i=0;i<Num_cloaking_walls;i++) { //find door
583 d = &CloakingWalls[i];
585 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
589 Assert(i<Num_cloaking_walls); //didn't find door!
590 Assert( d!=NULL ); // Get John!
592 d->time = CLOAKING_WALL_TIME - d->time;
595 else if (w->state == WALL_DOOR_CLOSED) { //create new door
596 d = &CloakingWalls[Num_cloaking_walls];
598 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
599 Int3(); //ran out of cloaking wall slots
600 /* what is this _doing_ here?
601 w->type = WALL_CLOSED;
602 Walls[csegp->sides[Connectside].wall_num].type = WALL_CLOSED;
606 Num_cloaking_walls++;
609 Int3(); //unexpected wall state
613 w->state = WALL_DOOR_DECLOAKING;
615 // So that door can't be shot while opening
616 csegp = &Segments[seg->children[side]];
617 Connectside = find_connect_side(seg, csegp);
618 Assert(Connectside != -1);
620 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_DECLOAKING;
622 d->front_wallnum = seg->sides[side].wall_num;
623 d->back_wallnum = csegp->sides[Connectside].wall_num;
625 Assert( seg-Segments != -1);
627 Assert(w->linked_wall == -1);
629 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
631 compute_center_point_on_side(&cp, seg, side );
632 digi_link_sound_to_pos( SOUND_WALL_CLOAK_OFF, seg-Segments, side, &cp, 0, F1_0 );
636 d->front_ls[i] = seg->sides[side].uvls[i].l;
637 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
641 //-----------------------------------------------------------------
642 // This function closes the specified door and restores the closed
643 // door texture. This is called when the animation is done
644 void wall_close_door_num(int door_num)
650 d = &ActiveDoors[door_num];
652 for (p=0;p<d->n_parts;p++) {
654 int Connectside, side;
655 segment *csegp, *seg;
657 w = &Walls[d->front_wallnum[p]];
659 seg = &Segments[w->segnum];
662 Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall
664 csegp = &Segments[seg->children[side]];
665 Connectside = find_connect_side(seg, csegp);
666 Assert(Connectside != -1);
668 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED;
669 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSED;
671 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0);
675 for (i=door_num;i<Num_open_doors;i++)
676 ActiveDoors[i] = ActiveDoors[i+1];
682 int check_poke(int objnum,int segnum,int side)
684 object *obj = &Objects[objnum];
686 //note: don't let objects with zero size block door
688 if (obj->size && get_seg_masks(&obj->pos,segnum,obj->size).sidemask & (1<<side))
689 return 1; //pokes through side!
691 return 0; //does not!
695 //returns true of door in unobjstructed (& thus can close)
696 int is_door_free(segment *seg,int side)
702 csegp = &Segments[seg->children[side]];
703 Connectside = find_connect_side(seg, csegp);
704 Assert(Connectside != -1);
706 //go through each object in each of two segments, and see if
707 //it pokes into the connecting seg
709 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
710 if (Objects[objnum].type!=OBJ_WEAPON && Objects[objnum].type!=OBJ_FIREBALL && check_poke(objnum,seg-Segments,side))
713 for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next)
714 if (Objects[objnum].type!=OBJ_WEAPON && Objects[objnum].type!=OBJ_FIREBALL && check_poke(objnum,csegp-Segments,Connectside))
717 return 1; //doorway is free!
722 //-----------------------------------------------------------------
724 void wall_close_door(segment *seg, int side)
731 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
733 w = &Walls[seg->sides[side].wall_num];
735 if ((w->state == WALL_DOOR_CLOSING) || //already closing
736 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
737 (w->state == WALL_DOOR_CLOSED)) //closed
740 if (!is_door_free(seg,side))
743 if (w->state == WALL_DOOR_OPENING) { //reuse door
749 for (i=0;i<Num_open_doors;i++) { //find door
753 if (d->front_wallnum[0]==w-Walls || d->back_wallnum[0]==w-Walls || (d->n_parts==2 && (d->front_wallnum[1]==w-Walls || d->back_wallnum[1]==w-Walls)))
757 Assert(i<Num_open_doors); //didn't find door!
758 Assert( d!=NULL ); // Get John!
760 d->time = WallAnims[w->clip_num].play_time - d->time;
766 else { //create new door
767 Assert(w->state == WALL_DOOR_OPEN);
768 d = &ActiveDoors[Num_open_doors];
771 Assert( Num_open_doors < MAX_DOORS );
774 w->state = WALL_DOOR_CLOSING;
776 // So that door can't be shot while opening
777 csegp = &Segments[seg->children[side]];
778 Connectside = find_connect_side(seg, csegp);
779 Assert(Connectside != -1);
781 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
783 d->front_wallnum[0] = seg->sides[side].wall_num;
784 d->back_wallnum[0] = csegp->sides[Connectside].wall_num;
786 Assert( seg-Segments != -1);
788 if (Newdemo_state == ND_STATE_RECORDING) {
789 newdemo_record_door_opening(seg-Segments, side);
792 if (w->linked_wall != -1) {
793 Int3(); //don't think we ever used linked walls
799 if ( Newdemo_state != ND_STATE_PLAYBACK )
801 // NOTE THE LINK TO ABOVE!!!!
803 compute_center_point_on_side(&cp, seg, side );
804 if (WallAnims[w->clip_num].open_sound > -1 )
805 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
810 //-----------------------------------------------------------------
811 // Animates opening of a door.
812 // Called in the game loop.
813 void do_door_open(int door_num)
818 Assert(door_num != -1); //Trying to do_door_open on illegal door
820 d = &ActiveDoors[door_num];
822 for (p=0;p<d->n_parts;p++) {
824 int Connectside, side;
825 segment *csegp, *seg;
826 fix time_elapsed, time_total, one_frame;
829 w = &Walls[d->front_wallnum[p]];
830 kill_stuck_objects(d->front_wallnum[p]);
831 kill_stuck_objects(d->back_wallnum[p]);
833 seg = &Segments[w->segnum];
836 Assert(seg->sides[side].wall_num != -1); //Trying to do_door_open on illegal wall
838 csegp = &Segments[seg->children[side]];
839 Connectside = find_connect_side(seg, csegp);
840 Assert(Connectside != -1);
842 d->time += FrameTime;
844 time_elapsed = d->time;
845 n = WallAnims[w->clip_num].num_frames;
846 time_total = WallAnims[w->clip_num].play_time;
848 one_frame = time_total/n;
850 i = time_elapsed/one_frame;
853 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
856 Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED;
857 Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED;
861 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1);
863 // If our door is not automatic just remove it from the list.
864 if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) {
865 for (i=door_num;i<Num_open_doors;i++)
866 ActiveDoors[i] = ActiveDoors[i+1];
868 Walls[seg->sides[side].wall_num].state = WALL_DOOR_OPEN;
869 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPEN;
873 Walls[seg->sides[side].wall_num].state = WALL_DOOR_WAITING;
874 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING;
876 ActiveDoors[Num_open_doors].time = 0; //counts up
884 //-----------------------------------------------------------------
885 // Animates and processes the closing of a door.
886 // Called from the game loop.
887 void do_door_close(int door_num)
893 Assert(door_num != -1); //Trying to do_door_open on illegal door
895 d = &ActiveDoors[door_num];
897 w = &Walls[d->front_wallnum[0]];
899 //check for objects in doorway before closing
900 if (w->flags & WALL_DOOR_AUTO)
901 if (!is_door_free(&Segments[w->segnum],w->sidenum)) {
902 digi_kill_sound_linked_to_segment(w->segnum,w->sidenum,-1);
903 wall_open_door(&Segments[w->segnum],w->sidenum); //re-open door
907 for (p=0;p<d->n_parts;p++) {
909 int Connectside, side;
910 segment *csegp, *seg;
911 fix time_elapsed, time_total, one_frame;
914 w = &Walls[d->front_wallnum[p]];
916 seg = &Segments[w->segnum];
919 if (seg->sides[side].wall_num == -1) {
920 mprintf((0, "Trying to do_door_close on Illegal wall\n"));
924 //if here, must be auto door
925 // Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO);
926 //don't assert here, because now we have triggers to close non-auto doors
928 // Otherwise, close it.
929 csegp = &Segments[seg->children[side]];
930 Connectside = find_connect_side(seg, csegp);
931 Assert(Connectside != -1);
934 if ( Newdemo_state != ND_STATE_PLAYBACK )
935 // NOTE THE LINK TO ABOVE!!
936 if (p==0) //only play one sound for linked doors
937 if ( d->time==0 ) { //first time
939 compute_center_point_on_side(&cp, seg, side );
940 if (WallAnims[w->clip_num].close_sound > -1 )
941 digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, seg-Segments, side, &cp, 0, F1_0 );
944 d->time += FrameTime;
946 time_elapsed = d->time;
947 n = WallAnims[w->clip_num].num_frames;
948 time_total = WallAnims[w->clip_num].play_time;
950 one_frame = time_total/n;
952 i = n-time_elapsed/one_frame-1;
955 Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED;
956 Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED;
961 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
963 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING;
964 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
966 ActiveDoors[Num_open_doors].time = 0; //counts up
969 wall_close_door_num(door_num);
974 //-----------------------------------------------------------------
975 // Turns off an illusionary wall (This will be used primarily for
976 // wall switches or triggers that can turn on/off illusionary walls.)
977 void wall_illusion_off(segment *seg, int side)
982 csegp = &Segments[seg->children[side]];
983 cside = find_connect_side(seg, csegp);
986 if (seg->sides[side].wall_num == -1) {
987 mprintf((0, "Trying to shut off illusion illegal wall\n"));
991 Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF;
992 Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF;
994 kill_stuck_objects(seg->sides[side].wall_num);
995 kill_stuck_objects(csegp->sides[cside].wall_num);
998 //-----------------------------------------------------------------
999 // Turns on an illusionary wall (This will be used primarily for
1000 // wall switches or triggers that can turn on/off illusionary walls.)
1001 void wall_illusion_on(segment *seg, int side)
1006 csegp = &Segments[seg->children[side]];
1007 cside = find_connect_side(seg, csegp);
1008 Assert(cside != -1);
1010 if (seg->sides[side].wall_num == -1) {
1011 mprintf((0, "Trying to turn on illusion illegal wall\n"));
1015 Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF;
1016 Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF;
1019 // -----------------------------------------------------------------------------
1020 // Allowed to open the normally locked special boss door if in multiplayer mode.
1021 int special_boss_opening_allowed(int segnum, int sidenum)
1023 if (Game_mode & GM_MULTI)
1024 return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE);
1029 //-----------------------------------------------------------------
1030 // Determines what happens when a wall is shot
1031 //returns info about wall. see wall.h for codes
1032 //obj is the object that hit...either a weapon or the player himself
1033 //playernum is the number the player who hit the wall or fired the weapon,
1034 //or -1 if a robot fired the weapon
1035 int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj )
1040 Assert (seg-Segments != -1);
1042 // If it is not a "wall" then just return.
1043 if ( seg->sides[side].wall_num < 0 )
1044 return WHP_NOT_SPECIAL;
1046 w = &Walls[seg->sides[side].wall_num];
1048 if ( Newdemo_state == ND_STATE_RECORDING )
1049 newdemo_record_wall_hit_process( seg-Segments, side, damage, playernum );
1051 if (w->type == WALL_BLASTABLE) {
1052 if (obj->ctype.laser_info.parent_type == OBJ_PLAYER)
1053 wall_damage(seg, side, damage);
1054 return WHP_BLASTABLE;
1057 if (playernum != Player_num) //return if was robot fire
1058 return WHP_NOT_SPECIAL;
1060 Assert( playernum > -1 );
1062 // Determine whether player is moving forward. If not, don't say negative
1063 // messages because he probably didn't intentionally hit the door.
1064 if (obj->type == OBJ_PLAYER)
1065 show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0);
1066 else if (obj->type == OBJ_ROBOT)
1068 else if ((obj->type == OBJ_WEAPON) && (obj->ctype.laser_info.parent_type == OBJ_ROBOT))
1073 if (w->keys == KEY_BLUE)
1074 if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) {
1075 if ( playernum==Player_num )
1077 HUD_init_message("%s %s",TXT_BLUE,TXT_ACCESS_DENIED);
1081 if (w->keys == KEY_RED)
1082 if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) {
1083 if ( playernum==Player_num )
1085 HUD_init_message("%s %s",TXT_RED,TXT_ACCESS_DENIED);
1089 if (w->keys == KEY_GOLD)
1090 if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) {
1091 if ( playernum==Player_num )
1093 HUD_init_message("%s %s",TXT_YELLOW,TXT_ACCESS_DENIED);
1097 if (w->type == WALL_DOOR)
1099 if ((w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(seg-Segments, side)) ) {
1100 if ( playernum==Player_num )
1102 HUD_init_message(TXT_CANT_OPEN_DOOR);
1106 if (w->state != WALL_DOOR_OPENING)
1108 wall_open_door(seg, side);
1110 if (Game_mode & GM_MULTI)
1111 multi_send_door_open(seg-Segments, side,w->flags);
1119 return WHP_NOT_SPECIAL; //default is treat like normal wall
1122 //-----------------------------------------------------------------
1123 // Opens doors/destroys wall/shuts off triggers.
1124 void wall_toggle(segment *seg, int side)
1128 if (seg - Segments > Highest_segment_index)
1130 Warning("Can't toggle side %d of segment %d - nonexistent segment!\n", side, seg-Segments);
1133 Assert( side < MAX_SIDES_PER_SEGMENT );
1135 wall_num = seg->sides[side].wall_num;
1137 if (wall_num == -1) {
1138 mprintf((0, "Illegal wall_toggle\n"));
1142 if ( Newdemo_state == ND_STATE_RECORDING )
1143 newdemo_record_wall_toggle(seg-Segments, side );
1145 if (Walls[wall_num].type == WALL_BLASTABLE)
1146 wall_destroy(seg, side);
1148 if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED))
1149 wall_open_door(seg, side);
1154 //-----------------------------------------------------------------
1155 // Tidy up Walls array for load/save purposes.
1160 if (Num_walls < 0) {
1161 mprintf((0, "Illegal Num_walls\n"));
1165 for (i=Num_walls;i<MAX_WALLS;i++) {
1166 Walls[i].type = WALL_NORMAL;
1169 Walls[i].trigger = -1;
1170 Walls[i].clip_num = -1;
1174 void do_cloaking_wall_frame(int cloaking_wall_num)
1177 wall *wfront,*wback;
1179 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1181 d = &CloakingWalls[cloaking_wall_num];
1182 wfront = &Walls[d->front_wallnum];
1183 wback = &Walls[d->back_wallnum];
1185 d->time += FrameTime;
1187 if (d->time > CLOAKING_WALL_TIME) {
1190 wfront->type = wback->type = WALL_OPEN;
1191 wfront->state = wback->state = WALL_DOOR_CLOSED; //why closed? why not?
1193 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1194 CloakingWalls[i] = CloakingWalls[i+1];
1195 Num_cloaking_walls--;
1198 else if (d->time > CLOAKING_WALL_TIME/2) {
1199 int old_type=wfront->type;
1201 wfront->cloak_value = wback->cloak_value = ((d->time - CLOAKING_WALL_TIME/2) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1203 if (old_type != WALL_CLOAKED) { //just switched
1206 wfront->type = wback->type = WALL_CLOAKED;
1209 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1210 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1218 light_scale = fixdiv(CLOAKING_WALL_TIME/2-d->time,CLOAKING_WALL_TIME/2);
1221 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1222 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1226 if ( Newdemo_state == ND_STATE_RECORDING )
1227 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);
1231 void do_decloaking_wall_frame(int cloaking_wall_num)
1234 wall *wfront,*wback;
1236 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1238 d = &CloakingWalls[cloaking_wall_num];
1239 wfront = &Walls[d->front_wallnum];
1240 wback = &Walls[d->back_wallnum];
1242 d->time += FrameTime;
1244 if (d->time > CLOAKING_WALL_TIME) {
1247 wfront->state = wback->state = WALL_DOOR_CLOSED;
1250 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1251 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1254 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1255 CloakingWalls[i] = CloakingWalls[i+1];
1256 Num_cloaking_walls--;
1259 else if (d->time > CLOAKING_WALL_TIME/2) { //fading in
1263 wfront->type = wback->type = WALL_CLOSED;
1265 light_scale = fixdiv(d->time-CLOAKING_WALL_TIME/2,CLOAKING_WALL_TIME/2);
1268 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1269 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1272 else { //cloaking in
1273 wfront->cloak_value = wback->cloak_value = ((CLOAKING_WALL_TIME/2 - d->time) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1274 wfront->type = wback->type = WALL_CLOAKED;
1277 if ( Newdemo_state == ND_STATE_RECORDING )
1278 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);
1282 void wall_frame_process()
1286 for (i=0;i<Num_open_doors;i++) {
1290 d = &ActiveDoors[i];
1291 w = &Walls[d->front_wallnum[0]];
1293 if (w->state == WALL_DOOR_OPENING)
1295 else if (w->state == WALL_DOOR_CLOSING)
1297 else if (w->state == WALL_DOOR_WAITING) {
1298 d->time += FrameTime;
1300 //set flags to fix occatsional netgame problem where door is
1301 //waiting to close but open flag isn't set
1302 Assert(d->n_parts == 1);
1303 w->flags |= WALL_DOOR_OPENED;
1304 Walls[d->back_wallnum[0]].flags |= WALL_DOOR_OPENED;
1306 if (d->time > DOOR_WAIT_TIME && is_door_free(&Segments[w->segnum],w->sidenum)) {
1307 w->state = WALL_DOOR_CLOSING;
1311 else if (w->state == WALL_DOOR_CLOSED || w->state == WALL_DOOR_OPEN) {
1312 //this shouldn't happen. if the wall is in one of these states,
1313 //there shouldn't be an activedoor entry for it. So we'll kill
1314 //the activedoor entry. Tres simple.
1316 Int3(); //a bad thing has happened, but I'll try to fix it up
1317 for (t=i;t<Num_open_doors;t++)
1318 ActiveDoors[t] = ActiveDoors[t+1];
1323 for (i=0;i<Num_cloaking_walls;i++) {
1327 d = &CloakingWalls[i];
1328 w = &Walls[d->front_wallnum];
1330 if (w->state == WALL_DOOR_CLOAKING)
1331 do_cloaking_wall_frame(i);
1332 else if (w->state == WALL_DOOR_DECLOAKING)
1333 do_decloaking_wall_frame(i);
1335 Int3(); //unexpected wall state
1339 int Num_stuck_objects=0;
1341 stuckobj Stuck_objects[MAX_STUCK_OBJECTS];
1343 // An object got stuck in a door (like a flare).
1344 // Add global entry.
1345 void add_stuck_object(object *objp, int segnum, int sidenum)
1350 wallnum = Segments[segnum].sides[sidenum].wall_num;
1352 if (wallnum != -1) {
1353 if (Walls[wallnum].flags & WALL_BLASTED)
1354 objp->flags |= OF_SHOULD_BE_DEAD;
1356 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1357 if (Stuck_objects[i].wallnum == -1) {
1358 Stuck_objects[i].wallnum = wallnum;
1359 Stuck_objects[i].objnum = objp-Objects;
1360 Stuck_objects[i].signature = objp->signature;
1361 // mprintf((0, "Added wall %i at index %i\n", wallnum, i));
1362 Num_stuck_objects++;
1366 if (i == MAX_STUCK_OBJECTS)
1367 mprintf((1, "Warning: Unable to add object %i which got stuck in wall %i to Stuck_objects\n", objp-Objects, wallnum));
1374 // --------------------------------------------------------------------------------------------------
1375 // Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here.
1376 // Removes up to one/frame.
1377 void remove_obsolete_stuck_objects(void)
1381 // Safety and efficiency code. If no stuck objects, should never get inside the IF, but this is faster.
1382 if (!Num_stuck_objects)
1385 objnum = FrameCount % MAX_STUCK_OBJECTS;
1387 if (Stuck_objects[objnum].wallnum != -1)
1388 if ((Walls[Stuck_objects[objnum].wallnum].state != WALL_DOOR_CLOSED) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) {
1389 Num_stuck_objects--;
1390 Objects[Stuck_objects[objnum].objnum].lifeleft = F1_0/8;
1391 Stuck_objects[objnum].wallnum = -1;
1396 extern void flush_fcd_cache(void);
1398 // ----------------------------------------------------------------------------------------------------
1399 // Door with wall index wallnum is opening, kill all objects stuck in it.
1400 void kill_stuck_objects(int wallnum)
1404 if (Num_stuck_objects == 0) {
1408 Num_stuck_objects=0;
1410 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1411 if (Stuck_objects[i].wallnum == wallnum) {
1412 if (Objects[Stuck_objects[i].objnum].type == OBJ_WEAPON) {
1413 Objects[Stuck_objects[i].objnum].lifeleft = F1_0/8;
1415 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));
1416 // Int3(); // What? This looks bad. Object is not a weapon and it is stuck in a wall!
1417 Stuck_objects[i].wallnum = -1;
1418 } else if (Stuck_objects[i].wallnum != -1) {
1419 Num_stuck_objects++;
1421 // Ok, this is awful, but we need to do things whenever a door opens/closes/disappears, etc.
1427 // -- unused -- // -----------------------------------------------------------------------------------
1428 // -- unused -- // Return object id of first flare found embedded in segp:sidenum.
1429 // -- unused -- // If no flare, return -1.
1430 // -- unused -- int contains_flare(segment *segp, int sidenum)
1432 // -- unused -- int i;
1434 // -- unused -- for (i=0; i<Num_stuck_objects; i++) {
1435 // -- unused -- object *objp = &Objects[Stuck_objects[i].objnum];
1437 // -- unused -- if ((objp->type == OBJ_WEAPON) && (objp->id == FLARE_ID)) {
1438 // -- unused -- if (Walls[Stuck_objects[i].wallnum].segnum == segp-Segments)
1439 // -- unused -- if (Walls[Stuck_objects[i].wallnum].sidenum == sidenum)
1440 // -- unused -- return objp-Objects;
1444 // -- unused -- return -1;
1447 // -----------------------------------------------------------------------------------
1448 // Initialize stuck objects array. Called at start of level
1449 void init_stuck_objects(void)
1453 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1454 Stuck_objects[i].wallnum = -1;
1456 Num_stuck_objects = 0;
1459 // -----------------------------------------------------------------------------------
1460 // Clear out all stuck objects. Called for a new ship
1461 void clear_stuck_objects(void)
1465 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1466 if (Stuck_objects[i].wallnum != -1) {
1469 objnum = Stuck_objects[i].objnum;
1471 if ((Objects[objnum].type == OBJ_WEAPON) && (Objects[objnum].id == FLARE_ID))
1472 Objects[objnum].lifeleft = F1_0/8;
1474 Stuck_objects[i].wallnum = -1;
1476 Num_stuck_objects--;
1480 Assert(Num_stuck_objects == 0);
1484 // -----------------------------------------------------------------------------------
1485 #define MAX_BLAST_GLASS_DEPTH 5
1487 void bng_process_segment(object *objp, fix damage, segment *segp, int depth, byte *visited)
1491 if (depth > MAX_BLAST_GLASS_DEPTH)
1496 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1501 // Process only walls which have glass.
1502 if ((tm=segp->sides[sidenum].tmap_num2) != 0) {
1505 tm &= 0x3fff; //tm without flags
1507 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))) {
1508 compute_center_point_on_side(&pnt, segp, sidenum);
1509 dist = vm_vec_dist_quick(&pnt, &objp->pos);
1510 if (dist < damage/2) {
1511 dist = find_connected_distance(&pnt, segp-Segments, &objp->pos, objp->segnum, MAX_BLAST_GLASS_DEPTH, WID_RENDPAST_FLAG);
1512 if ((dist > 0) && (dist < damage/2))
1513 check_effect_blowup(segp, sidenum, &pnt, &Objects[objp->ctype.laser_info.parent_num], 1);
1519 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1520 int segnum = segp->children[i];
1523 if (!visited[segnum]) {
1524 if (WALL_IS_DOORWAY(segp, i) & WID_FLY_FLAG) {
1525 visited[segnum] = 1;
1526 bng_process_segment(objp, damage, &Segments[segnum], depth, visited);
1533 // -----------------------------------------------------------------------------------
1534 // objp is going to detonate
1535 // blast nearby monitors, lights, maybe other things
1536 void blast_nearby_glass(object *objp, fix damage)
1539 byte visited[MAX_SEGMENTS];
1542 cursegp = &Segments[objp->segnum];
1543 for (i=0; i<=Highest_segment_index; i++)
1546 visited[objp->segnum] = 1;
1547 bng_process_segment(objp, damage, cursegp, 0, visited);
1552 #define MAX_CLIP_FRAMES_D1 20
1555 * reads a wclip structure from a CFILE
1557 int wclip_read_n_d1(wclip *wc, int n, CFILE *fp)
1561 for (i = 0; i < n; i++) {
1562 wc[i].play_time = cfile_read_fix(fp);
1563 wc[i].num_frames = cfile_read_short(fp);
1564 for (j = 0; j < MAX_CLIP_FRAMES_D1; j++)
1565 wc[i].frames[j] = cfile_read_short(fp);
1566 wc[i].open_sound = cfile_read_short(fp);
1567 wc[i].close_sound = cfile_read_short(fp);
1568 wc[i].flags = cfile_read_short(fp);
1569 cfread(wc[i].filename, 13, 1, fp);
1570 wc[i].pad = cfile_read_byte(fp);
1575 #ifndef FAST_FILE_IO
1577 * reads a wclip structure from a CFILE
1579 int wclip_read_n(wclip *wc, int n, CFILE *fp)
1583 for (i = 0; i < n; i++) {
1584 wc[i].play_time = cfile_read_fix(fp);
1585 wc[i].num_frames = cfile_read_short(fp);
1586 for (j = 0; j < MAX_CLIP_FRAMES; j++)
1587 wc[i].frames[j] = cfile_read_short(fp);
1588 wc[i].open_sound = cfile_read_short(fp);
1589 wc[i].close_sound = cfile_read_short(fp);
1590 wc[i].flags = cfile_read_short(fp);
1591 cfread(wc[i].filename, 13, 1, fp);
1592 wc[i].pad = cfile_read_byte(fp);
1598 * reads a v16_wall structure from a CFILE
1600 extern void v16_wall_read(v16_wall *w, CFILE *fp)
1602 w->type = cfile_read_byte(fp);
1603 w->flags = cfile_read_byte(fp);
1604 w->hps = cfile_read_fix(fp);
1605 w->trigger = cfile_read_byte(fp);
1606 w->clip_num = cfile_read_byte(fp);
1607 w->keys = cfile_read_byte(fp);
1611 * reads a v19_wall structure from a CFILE
1613 extern void v19_wall_read(v19_wall *w, CFILE *fp)
1615 w->segnum = cfile_read_int(fp);
1616 w->sidenum = cfile_read_int(fp);
1617 w->type = cfile_read_byte(fp);
1618 w->flags = cfile_read_byte(fp);
1619 w->hps = cfile_read_fix(fp);
1620 w->trigger = cfile_read_byte(fp);
1621 w->clip_num = cfile_read_byte(fp);
1622 w->keys = cfile_read_byte(fp);
1623 w->linked_wall = cfile_read_int(fp);
1627 * reads a wall structure from a CFILE
1629 extern void wall_read(wall *w, CFILE *fp)
1631 w->segnum = cfile_read_int(fp);
1632 w->sidenum = cfile_read_int(fp);
1633 w->hps = cfile_read_fix(fp);
1634 w->linked_wall = cfile_read_int(fp);
1635 w->type = cfile_read_byte(fp);
1636 w->flags = cfile_read_byte(fp);
1637 w->state = cfile_read_byte(fp);
1638 w->trigger = cfile_read_byte(fp);
1639 w->clip_num = cfile_read_byte(fp);
1640 w->keys = cfile_read_byte(fp);
1641 w->controlling_trigger = cfile_read_byte(fp);
1642 w->cloak_value = cfile_read_byte(fp);
1646 * reads a v19_door structure from a CFILE
1648 extern void v19_door_read(v19_door *d, CFILE *fp)
1650 d->n_parts = cfile_read_int(fp);
1651 d->seg[0] = cfile_read_short(fp);
1652 d->seg[1] = cfile_read_short(fp);
1653 d->side[0] = cfile_read_short(fp);
1654 d->side[1] = cfile_read_short(fp);
1655 d->type[0] = cfile_read_short(fp);
1656 d->type[1] = cfile_read_short(fp);
1657 d->open = cfile_read_fix(fp);
1661 * reads an active_door structure from a CFILE
1663 extern void active_door_read(active_door *ad, CFILE *fp)
1665 ad->n_parts = cfile_read_int(fp);
1666 ad->front_wallnum[0] = cfile_read_short(fp);
1667 ad->front_wallnum[1] = cfile_read_short(fp);
1668 ad->back_wallnum[0] = cfile_read_short(fp);
1669 ad->back_wallnum[1] = cfile_read_short(fp);
1670 ad->time = cfile_read_fix(fp);