2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Destroyable wall stuff
50 #include "laser.h" // For seeing if a flare is stuck in a wall.
55 #include "editor/editor.h"
58 // Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK.
59 #define BOSS_LOCKED_DOOR_LEVEL 7
60 #define BOSS_LOCKED_DOOR_SEG 595
61 #define BOSS_LOCKED_DOOR_SIDE 5
63 wall Walls[MAX_WALLS]; // Master walls array
64 int Num_walls=0; // Number of walls
66 wclip WallAnims[MAX_WALL_ANIMS]; // Wall animations
68 //--unused-- int walls_bm_num[MAX_WALL_ANIMS];
70 //door Doors[MAX_DOORS]; // Master doors array
72 active_door ActiveDoors[MAX_DOORS];
73 int Num_open_doors; // Number of open doors
75 #define CLOAKING_WALL_TIME f1_0
77 #define MAX_CLOAKING_WALLS 10
78 cloaking_wall CloakingWalls[MAX_CLOAKING_WALLS];
79 int Num_cloaking_walls;
81 //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS];
83 //#define BM_FLAG_TRANSPARENT 1
84 //#define BM_FLAG_SUPER_TRANSPARENT 2
87 char Wall_names[7][10] = {
98 // Function prototypes
99 void kill_stuck_objects(int wallnum);
103 // This function determines whether the current segment/side is transparent
106 int check_transparency( segment * seg, int side )
108 if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) {
109 if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT )
115 if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT )
121 //-----------------------------------------------------------------
122 // This function checks whether we can fly through the given side.
123 // In other words, whether or not we have a 'doorway'
127 // WID_RENDPAST_FLAG 4
129 // WID_WALL 2 // 0/1/0 wall
130 // WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
131 // WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
132 // WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
133 // WID_NO_WALL 5 // 1/0/1 no wall, can fly through
134 int wall_is_doorway ( segment * seg, int side )
138 //--Covered by macro // No child.
139 //--Covered by macro if (seg->children[side] == -1)
140 //--Covered by macro return WID_WALL;
142 //--Covered by macro if (seg->children[side] == -2)
143 //--Covered by macro return WID_EXTERNAL_FLAG;
145 //--Covered by macro // No wall present.
146 //--Covered by macro if (seg->sides[side].wall_num == -1)
147 //--Covered by macro return WID_NO_WALL;
149 Assert(SEGMENT_NUMBER(seg) >= 0 && SEGMENT_NUMBER(seg) <= Highest_segment_index);
150 Assert(side>=0 && side<6);
152 type = Walls[seg->sides[side].wall_num].type;
153 flags = Walls[seg->sides[side].wall_num].flags;
155 if (type == WALL_OPEN)
158 if (type == WALL_ILLUSION) {
159 if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF)
162 if (check_transparency( seg, side))
163 return WID_TRANSILLUSORY_WALL;
165 return WID_ILLUSORY_WALL;
169 if (type == WALL_BLASTABLE) {
170 if (flags & WALL_BLASTED)
171 return WID_TRANSILLUSORY_WALL;
173 if (check_transparency( seg, side))
174 return WID_TRANSPARENT_WALL;
179 if (flags & WALL_DOOR_OPENED)
180 return WID_TRANSILLUSORY_WALL;
182 if (type == WALL_CLOAKED)
183 return WID_RENDER_FLAG | WID_RENDPAST_FLAG | WID_CLOAKED_FLAG;
185 state = Walls[seg->sides[side].wall_num].state;
186 if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING))
187 return WID_TRANSPARENT_WALL;
189 // If none of the above flags are set, there is no doorway.
190 if (check_transparency( seg, side))
191 return WID_TRANSPARENT_WALL;
193 return WID_WALL; // There are children behind the door.
197 //-----------------------------------------------------------------
198 // Initializes all the walls (in other words, no special walls)
204 for (i=0;i<MAX_WALLS;i++) {
205 Walls[i].segnum = Walls[i].sidenum = -1;
206 Walls[i].type = WALL_NORMAL;
209 Walls[i].trigger = -1;
210 Walls[i].clip_num = -1;
211 Walls[i].linked_wall = -1;
214 Num_cloaking_walls = 0;
218 //-----------------------------------------------------------------
219 // Initializes one wall.
220 void wall_reset(segment *seg, int side)
224 i = seg->sides[side].wall_num;
227 mprintf((0, "Resetting Illegal Wall\n"));
231 Walls[i].segnum = SEGMENT_NUMBER(seg);
232 Walls[i].sidenum = side;
233 Walls[i].type = WALL_NORMAL;
236 Walls[i].trigger = -1;
237 Walls[i].clip_num = -1;
238 Walls[i].linked_wall = -1;
242 //set the tmap_num or tmap_num2 field for a wall/door
243 void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num)
245 wclip *anim = &WallAnims[anim_num];
246 int tmap = anim->frames[frame_num];
248 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
250 if (anim->flags & WCF_TMAP1) {
251 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap;
252 if ( Newdemo_state == ND_STATE_RECORDING )
253 newdemo_record_wall_set_tmap_num1(SEGMENT_NUMBER(seg), side, SEGMENT_NUMBER(csegp), cside, tmap);
255 Assert(tmap!=0 && seg->sides[side].tmap_num2!=0);
256 seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap;
257 if ( Newdemo_state == ND_STATE_RECORDING )
258 newdemo_record_wall_set_tmap_num2(SEGMENT_NUMBER(seg), side, SEGMENT_NUMBER(csegp), cside, tmap);
263 // -------------------------------------------------------------------------------
264 //when the wall has used all its hitpoints, this will destroy it
265 void blast_blastable_wall(segment *seg, int side)
271 Assert(seg->sides[side].wall_num != -1);
273 Walls[seg->sides[side].wall_num].hps = -1; //say it's blasted
275 csegp = &Segments[seg->children[side]];
276 Connectside = find_connect_side(seg, csegp);
277 Assert(Connectside != -1);
278 cwall_num = csegp->sides[Connectside].wall_num;
279 kill_stuck_objects(seg->sides[side].wall_num);
281 kill_stuck_objects(cwall_num);
283 //if this is an exploding wall, explode it
284 if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES)
285 explode_wall(SEGMENT_NUMBER(seg), side);
287 //if not exploding, set final frame, and make door passable
288 a = Walls[seg->sides[side].wall_num].clip_num;
289 n = WallAnims[a].num_frames;
290 wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1);
291 Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED;
293 Walls[cwall_num].flags |= WALL_BLASTED;
299 //-----------------------------------------------------------------
300 // Destroys a blastable wall.
301 void wall_destroy(segment *seg, int side)
303 Assert(seg->sides[side].wall_num != -1);
304 Assert(SEGMENT_NUMBER(seg) != 0);
306 if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
307 blast_blastable_wall( seg, side );
309 Error("Hey bub, you are trying to destroy an indestructable wall.");
312 //-----------------------------------------------------------------
313 // Deteriorate appearance of wall. (Changes bitmap (paste-ons))
314 void wall_damage(segment *seg, int side, fix damage)
316 int a, i, n, cwall_num;
318 if (seg->sides[side].wall_num == -1) {
319 mprintf((0, "Damaging illegal wall\n"));
323 if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE)
326 if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED) && Walls[seg->sides[side].wall_num].hps >= 0)
331 csegp = &Segments[seg->children[side]];
332 Connectside = find_connect_side(seg, csegp);
333 Assert(Connectside != -1);
334 cwall_num = csegp->sides[Connectside].wall_num;
335 Walls[seg->sides[side].wall_num].hps -= damage;
337 Walls[cwall_num].hps -= damage;
339 a = Walls[seg->sides[side].wall_num].clip_num;
340 n = WallAnims[a].num_frames;
342 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) {
343 blast_blastable_wall( seg, side );
345 if (Game_mode & GM_MULTI)
346 multi_send_door_open(SEGMENT_NUMBER(seg), side, Walls[seg->sides[side].wall_num].flags);
351 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*(n-i)/n) {
352 wall_set_tmap_num(seg,side,csegp,Connectside,a,i);
358 //-----------------------------------------------------------------
360 void wall_open_door(segment *seg, int side)
364 int Connectside, wall_num, cwall_num;
367 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
369 w = &Walls[seg->sides[side].wall_num];
370 wall_num = w - Walls;
371 //kill_stuck_objects(seg->sides[side].wall_num);
373 if ((w->state == WALL_DOOR_OPENING) || //already opening
374 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
375 (w->state == WALL_DOOR_OPEN)) //open, & staying open
378 if (w->state == WALL_DOOR_CLOSING) { //closing, so reuse door
384 for (i=0;i<Num_open_doors;i++) { //find door
388 if (d->front_wallnum[0]==w-Walls || d->back_wallnum[0]==wall_num ||
389 (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num)))
393 if (i>=Num_open_doors && (Game_mode & GM_MULTI))
396 Assert(i<Num_open_doors); //didn't find door!
397 Assert( d!=NULL ); // Get John!
399 d->time = WallAnims[w->clip_num].play_time - d->time;
405 else { //create new door
406 Assert(w->state == WALL_DOOR_CLOSED);
408 d = &ActiveDoors[Num_open_doors];
411 Assert( Num_open_doors < MAX_DOORS );
415 w->state = WALL_DOOR_OPENING;
417 // So that door can't be shot while opening
418 csegp = &Segments[seg->children[side]];
419 Connectside = find_connect_side(seg, csegp);
420 Assert(Connectside != -1);
421 cwall_num = csegp->sides[Connectside].wall_num;
423 Walls[cwall_num].state = WALL_DOOR_OPENING;
425 //kill_stuck_objects(csegp->sides[Connectside].wall_num);
427 d->front_wallnum[0] = seg->sides[side].wall_num;
428 d->back_wallnum[0] = cwall_num;
430 Assert( SEGMENT_NUMBER(seg) != -1 );
432 if (Newdemo_state == ND_STATE_RECORDING) {
433 newdemo_record_door_opening(SEGMENT_NUMBER(seg), side);
436 if (w->linked_wall != -1) {
440 w2 = &Walls[w->linked_wall];
441 seg2 = &Segments[w2->segnum];
443 Assert(w2->linked_wall == seg->sides[side].wall_num);
444 //Assert(!(w2->flags & WALL_DOOR_OPENING || w2->flags & WALL_DOOR_OPENED));
446 w2->state = WALL_DOOR_OPENING;
448 csegp = &Segments[seg2->children[w2->sidenum]];
449 Connectside = find_connect_side(seg2, csegp);
450 Assert(Connectside != -1);
452 Walls[cwall_num].state = WALL_DOOR_OPENING;
455 d->front_wallnum[1] = w->linked_wall;
456 d->back_wallnum[1] = cwall_num;
462 if ( Newdemo_state != ND_STATE_PLAYBACK )
464 // NOTE THE LINK TO ABOVE!!!!
466 compute_center_point_on_side(&cp, seg, side );
467 if (WallAnims[w->clip_num].open_sound > -1 )
468 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
473 //-----------------------------------------------------------------
474 // start the transition from closed -> open wall
475 void start_wall_cloak(segment *seg, int side)
483 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
485 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
487 w = &Walls[seg->sides[side].wall_num];
489 if (w->type == WALL_OPEN || w->state == WALL_DOOR_CLOAKING) //already open or cloaking
492 csegp = &Segments[seg->children[side]];
493 Connectside = find_connect_side(seg, csegp);
494 Assert(Connectside != -1);
495 cwall_num = csegp->sides[Connectside].wall_num;
497 if (w->state == WALL_DOOR_DECLOAKING) { //decloaking, so reuse door
503 for (i=0;i<Num_cloaking_walls;i++) { //find door
505 d = &CloakingWalls[i];
507 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
511 Assert(i<Num_cloaking_walls); //didn't find door!
512 Assert( d!=NULL ); // Get John!
514 d->time = CLOAKING_WALL_TIME - d->time;
517 else if (w->state == WALL_DOOR_CLOSED) { //create new door
518 d = &CloakingWalls[Num_cloaking_walls];
520 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
521 Int3(); //ran out of cloaking wall slots
524 Walls[cwall_num].type = WALL_OPEN;
527 Num_cloaking_walls++;
530 Int3(); //unexpected wall state
534 w->state = WALL_DOOR_CLOAKING;
536 Walls[cwall_num].state = WALL_DOOR_CLOAKING;
538 d->front_wallnum = seg->sides[side].wall_num;
539 d->back_wallnum = cwall_num;
541 Assert( SEGMENT_NUMBER(seg) != -1 );
543 Assert(w->linked_wall == -1);
545 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
547 compute_center_point_on_side(&cp, seg, side );
548 digi_link_sound_to_pos( SOUND_WALL_CLOAK_ON, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
552 d->front_ls[i] = seg->sides[side].uvls[i].l;
554 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
558 //-----------------------------------------------------------------
559 // start the transition from open -> closed wall
560 void start_wall_decloak(segment *seg, int side)
568 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
570 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
572 w = &Walls[seg->sides[side].wall_num];
574 if (w->type == WALL_CLOSED || w->state == WALL_DOOR_DECLOAKING) //already closed or decloaking
577 if (w->state == WALL_DOOR_CLOAKING) { //cloaking, so reuse door
583 for (i=0;i<Num_cloaking_walls;i++) { //find door
585 d = &CloakingWalls[i];
587 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
591 Assert(i<Num_cloaking_walls); //didn't find door!
592 Assert( d!=NULL ); // Get John!
594 d->time = CLOAKING_WALL_TIME - d->time;
597 else if (w->state == WALL_DOOR_CLOSED) { //create new door
598 d = &CloakingWalls[Num_cloaking_walls];
600 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
601 Int3(); //ran out of cloaking wall slots
602 /* what is this _doing_ here?
603 w->type = WALL_CLOSED;
604 Walls[csegp->sides[Connectside].wall_num].type = WALL_CLOSED;
608 Num_cloaking_walls++;
611 Int3(); //unexpected wall state
615 w->state = WALL_DOOR_DECLOAKING;
617 // So that door can't be shot while opening
618 csegp = &Segments[seg->children[side]];
619 Connectside = find_connect_side(seg, csegp);
620 Assert(Connectside != -1);
621 cwall_num = csegp->sides[Connectside].wall_num;
623 Walls[cwall_num].state = WALL_DOOR_DECLOAKING;
625 d->front_wallnum = seg->sides[side].wall_num;
626 d->back_wallnum = csegp->sides[Connectside].wall_num;
628 Assert( SEGMENT_NUMBER(seg) != -1 );
630 Assert(w->linked_wall == -1);
632 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
634 compute_center_point_on_side(&cp, seg, side );
635 digi_link_sound_to_pos( SOUND_WALL_CLOAK_OFF, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
639 d->front_ls[i] = seg->sides[side].uvls[i].l;
641 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
645 //-----------------------------------------------------------------
646 // This function closes the specified door and restores the closed
647 // door texture. This is called when the animation is done
648 void wall_close_door_num(int door_num)
654 d = &ActiveDoors[door_num];
656 for (p=0;p<d->n_parts;p++) {
658 int Connectside, side;
659 segment *csegp, *seg;
661 w = &Walls[d->front_wallnum[p]];
663 seg = &Segments[w->segnum];
666 Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall
668 csegp = &Segments[seg->children[side]];
669 Connectside = find_connect_side(seg, csegp);
670 Assert(Connectside != -1);
671 cwall_num = csegp->sides[Connectside].wall_num;
672 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED;
674 Walls[cwall_num].state = WALL_DOOR_CLOSED;
676 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0);
680 for (i=door_num;i<Num_open_doors;i++)
681 ActiveDoors[i] = ActiveDoors[i+1];
687 int check_poke(int objnum,int segnum,int side)
689 object *obj = &Objects[objnum];
691 //note: don't let objects with zero size block door
693 if (obj->size && get_seg_masks(&obj->pos, segnum, obj->size, __FILE__, __LINE__).sidemask & (1 << side))
694 return 1; //pokes through side!
696 return 0; //does not!
700 //returns true of door in unobjstructed (& thus can close)
701 int is_door_free(segment *seg,int side)
707 csegp = &Segments[seg->children[side]];
708 Connectside = find_connect_side(seg, csegp);
709 Assert(Connectside != -1);
711 //go through each object in each of two segments, and see if
712 //it pokes into the connecting seg
714 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
715 if (Objects[objnum].type != OBJ_WEAPON && Objects[objnum].type != OBJ_FIREBALL && check_poke(objnum, SEGMENT_NUMBER(seg), side))
718 for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next)
719 if (Objects[objnum].type != OBJ_WEAPON && Objects[objnum].type != OBJ_FIREBALL && check_poke(objnum, SEGMENT_NUMBER(csegp), Connectside))
722 return 1; //doorway is free!
727 //-----------------------------------------------------------------
729 void wall_close_door(segment *seg, int side)
733 int Connectside, wall_num, cwall_num;
736 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
738 w = &Walls[seg->sides[side].wall_num];
739 wall_num = w - Walls;
740 if ((w->state == WALL_DOOR_CLOSING) || //already closing
741 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
742 (w->state == WALL_DOOR_CLOSED)) //closed
745 if (!is_door_free(seg,side))
748 if (w->state == WALL_DOOR_OPENING) { //reuse door
754 for (i=0;i<Num_open_doors;i++) { //find door
758 if (d->front_wallnum[0]==wall_num || d->back_wallnum[0]==wall_num ||
759 (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num)))
763 Assert(i<Num_open_doors); //didn't find door!
764 Assert( d!=NULL ); // Get John!
766 d->time = WallAnims[w->clip_num].play_time - d->time;
772 else { //create new door
773 Assert(w->state == WALL_DOOR_OPEN);
774 d = &ActiveDoors[Num_open_doors];
777 Assert( Num_open_doors < MAX_DOORS );
780 w->state = WALL_DOOR_CLOSING;
782 // So that door can't be shot while opening
783 csegp = &Segments[seg->children[side]];
784 Connectside = find_connect_side(seg, csegp);
785 Assert(Connectside != -1);
786 cwall_num = csegp->sides[Connectside].wall_num;
788 Walls[cwall_num].state = WALL_DOOR_CLOSING;
790 d->front_wallnum[0] = seg->sides[side].wall_num;
791 d->back_wallnum[0] = cwall_num;
793 Assert( SEGMENT_NUMBER(seg) != -1 );
795 if (Newdemo_state == ND_STATE_RECORDING) {
796 newdemo_record_door_opening(SEGMENT_NUMBER(seg), side);
799 if (w->linked_wall != -1) {
800 Int3(); //don't think we ever used linked walls
806 if ( Newdemo_state != ND_STATE_PLAYBACK )
808 // NOTE THE LINK TO ABOVE!!!!
810 compute_center_point_on_side(&cp, seg, side );
811 if (WallAnims[w->clip_num].open_sound > -1 )
812 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
817 //-----------------------------------------------------------------
818 // Animates opening of a door.
819 // Called in the game loop.
820 void do_door_open(int door_num)
825 Assert(door_num != -1); //Trying to do_door_open on illegal door
827 d = &ActiveDoors[door_num];
829 for (p=0;p<d->n_parts;p++) {
831 int Connectside, side;
832 segment *csegp, *seg;
833 fix time_elapsed, time_total, one_frame;
836 w = &Walls[d->front_wallnum[p]];
837 kill_stuck_objects(d->front_wallnum[p]);
838 kill_stuck_objects(d->back_wallnum[p]);
840 seg = &Segments[w->segnum];
843 Assert(seg->sides[side].wall_num != -1); //Trying to do_door_open on illegal wall
845 csegp = &Segments[seg->children[side]];
846 Connectside = find_connect_side(seg, csegp);
847 Assert(Connectside != -1);
849 d->time += FrameTime;
851 time_elapsed = d->time;
852 n = WallAnims[w->clip_num].num_frames;
853 time_total = WallAnims[w->clip_num].play_time;
855 one_frame = time_total/n;
857 i = time_elapsed/one_frame;
860 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
863 Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED;
864 Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED;
868 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1);
870 // If our door is not automatic just remove it from the list.
871 if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) {
872 for (i=door_num;i<Num_open_doors;i++)
873 ActiveDoors[i] = ActiveDoors[i+1];
875 Walls[seg->sides[side].wall_num].state = WALL_DOOR_OPEN;
876 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPEN;
880 Walls[seg->sides[side].wall_num].state = WALL_DOOR_WAITING;
881 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING;
883 ActiveDoors[Num_open_doors].time = 0; //counts up
891 //-----------------------------------------------------------------
892 // Animates and processes the closing of a door.
893 // Called from the game loop.
894 void do_door_close(int door_num)
900 Assert(door_num != -1); //Trying to do_door_open on illegal door
902 d = &ActiveDoors[door_num];
904 w = &Walls[d->front_wallnum[0]];
906 //check for objects in doorway before closing
907 if (w->flags & WALL_DOOR_AUTO)
908 if (!is_door_free(&Segments[w->segnum],w->sidenum)) {
909 digi_kill_sound_linked_to_segment(w->segnum,w->sidenum,-1);
910 wall_open_door(&Segments[w->segnum],w->sidenum); //re-open door
914 for (p=0;p<d->n_parts;p++) {
916 int Connectside, side;
917 segment *csegp, *seg;
918 fix time_elapsed, time_total, one_frame;
921 w = &Walls[d->front_wallnum[p]];
923 seg = &Segments[w->segnum];
926 if (seg->sides[side].wall_num == -1) {
927 mprintf((0, "Trying to do_door_close on Illegal wall\n"));
931 //if here, must be auto door
932 // Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO);
933 //don't assert here, because now we have triggers to close non-auto doors
935 // Otherwise, close it.
936 csegp = &Segments[seg->children[side]];
937 Connectside = find_connect_side(seg, csegp);
938 Assert(Connectside != -1);
941 if ( Newdemo_state != ND_STATE_PLAYBACK )
942 // NOTE THE LINK TO ABOVE!!
943 if (p==0) //only play one sound for linked doors
944 if ( d->time==0 ) { //first time
946 compute_center_point_on_side(&cp, seg, side );
947 if (WallAnims[w->clip_num].close_sound > -1 )
948 digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
951 d->time += FrameTime;
953 time_elapsed = d->time;
954 n = WallAnims[w->clip_num].num_frames;
955 time_total = WallAnims[w->clip_num].play_time;
957 one_frame = time_total/n;
959 i = n-time_elapsed/one_frame-1;
962 Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED;
963 Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED;
968 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
970 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING;
971 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
973 ActiveDoors[Num_open_doors].time = 0; //counts up
976 wall_close_door_num(door_num);
981 //-----------------------------------------------------------------
982 // Turns off an illusionary wall (This will be used primarily for
983 // wall switches or triggers that can turn on/off illusionary walls.)
984 void wall_illusion_off(segment *seg, int side)
989 csegp = &Segments[seg->children[side]];
990 cside = find_connect_side(seg, csegp);
993 if (seg->sides[side].wall_num == -1) {
994 mprintf((0, "Trying to shut off illusion illegal wall\n"));
998 Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF;
999 Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF;
1001 kill_stuck_objects(seg->sides[side].wall_num);
1002 kill_stuck_objects(csegp->sides[cside].wall_num);
1005 //-----------------------------------------------------------------
1006 // Turns on an illusionary wall (This will be used primarily for
1007 // wall switches or triggers that can turn on/off illusionary walls.)
1008 void wall_illusion_on(segment *seg, int side)
1013 csegp = &Segments[seg->children[side]];
1014 cside = find_connect_side(seg, csegp);
1015 Assert(cside != -1);
1017 if (seg->sides[side].wall_num == -1) {
1018 mprintf((0, "Trying to turn on illusion illegal wall\n"));
1022 Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF;
1023 Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF;
1026 // -----------------------------------------------------------------------------
1027 // Allowed to open the normally locked special boss door if in multiplayer mode.
1028 int special_boss_opening_allowed(int segnum, int sidenum)
1030 if (Game_mode & GM_MULTI)
1031 return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE);
1036 //-----------------------------------------------------------------
1037 // Determines what happens when a wall is shot
1038 //returns info about wall. see wall.h for codes
1039 //obj is the object that hit...either a weapon or the player himself
1040 //playernum is the number the player who hit the wall or fired the weapon,
1041 //or -1 if a robot fired the weapon
1042 int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj )
1047 Assert( SEGMENT_NUMBER(seg) != -1 );
1049 // If it is not a "wall" then just return.
1050 if ( seg->sides[side].wall_num < 0 )
1051 return WHP_NOT_SPECIAL;
1053 w = &Walls[seg->sides[side].wall_num];
1055 if ( Newdemo_state == ND_STATE_RECORDING )
1056 newdemo_record_wall_hit_process( SEGMENT_NUMBER(seg), side, damage, playernum );
1058 if (w->type == WALL_BLASTABLE) {
1059 if (obj->ctype.laser_info.parent_type == OBJ_PLAYER)
1060 wall_damage(seg, side, damage);
1061 return WHP_BLASTABLE;
1064 if (playernum != Player_num) //return if was robot fire
1065 return WHP_NOT_SPECIAL;
1067 Assert( playernum > -1 );
1069 // Determine whether player is moving forward. If not, don't say negative
1070 // messages because he probably didn't intentionally hit the door.
1071 if (obj->type == OBJ_PLAYER)
1072 show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0);
1073 else if (obj->type == OBJ_ROBOT)
1075 else if ((obj->type == OBJ_WEAPON) && (obj->ctype.laser_info.parent_type == OBJ_ROBOT))
1080 if (w->keys == KEY_BLUE)
1081 if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) {
1082 if ( playernum==Player_num )
1084 HUD_init_message("%s %s",TXT_BLUE,TXT_ACCESS_DENIED);
1088 if (w->keys == KEY_RED)
1089 if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) {
1090 if ( playernum==Player_num )
1092 HUD_init_message("%s %s",TXT_RED,TXT_ACCESS_DENIED);
1096 if (w->keys == KEY_GOLD)
1097 if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) {
1098 if ( playernum==Player_num )
1100 HUD_init_message("%s %s",TXT_YELLOW,TXT_ACCESS_DENIED);
1104 if (w->type == WALL_DOOR)
1106 if ( (w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(SEGMENT_NUMBER(seg), side)) ) {
1107 if ( playernum==Player_num )
1109 HUD_init_message(TXT_CANT_OPEN_DOOR);
1113 if (w->state != WALL_DOOR_OPENING)
1115 wall_open_door(seg, side);
1117 if (Game_mode & GM_MULTI)
1118 multi_send_door_open(SEGMENT_NUMBER(seg), side, w->flags);
1126 return WHP_NOT_SPECIAL; //default is treat like normal wall
1129 //-----------------------------------------------------------------
1130 // Opens doors/destroys wall/shuts off triggers.
1131 void wall_toggle(segment *seg, int side)
1135 if (SEGMENT_NUMBER(seg) > Highest_segment_index)
1137 Warning("Can't toggle side %d of segment %d - nonexistent segment!\n", side, SEGMENT_NUMBER(seg));
1140 Assert( side < MAX_SIDES_PER_SEGMENT );
1142 wall_num = seg->sides[side].wall_num;
1144 if (wall_num == -1) {
1145 mprintf((0, "Illegal wall_toggle\n"));
1149 if ( Newdemo_state == ND_STATE_RECORDING )
1150 newdemo_record_wall_toggle( SEGMENT_NUMBER(seg), side );
1152 if (Walls[wall_num].type == WALL_BLASTABLE)
1153 wall_destroy(seg, side);
1155 if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED))
1156 wall_open_door(seg, side);
1161 //-----------------------------------------------------------------
1162 // Tidy up Walls array for load/save purposes.
1167 if (Num_walls < 0) {
1168 mprintf((0, "Illegal Num_walls\n"));
1172 for (i=Num_walls;i<MAX_WALLS;i++) {
1173 Walls[i].type = WALL_NORMAL;
1176 Walls[i].trigger = -1;
1177 Walls[i].clip_num = -1;
1181 void do_cloaking_wall_frame(int cloaking_wall_num)
1184 wall *wfront,*wback;
1186 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1188 d = &CloakingWalls[cloaking_wall_num];
1189 wfront = &Walls[d->front_wallnum];
1190 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1192 d->time += FrameTime;
1194 if (d->time > CLOAKING_WALL_TIME) {
1197 wfront->type = WALL_OPEN;
1198 wfront->state = WALL_DOOR_CLOSED; //why closed? why not?
1200 wback->type = WALL_OPEN;
1201 wback->state = WALL_DOOR_CLOSED; //why closed? why not?
1204 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1205 CloakingWalls[i] = CloakingWalls[i+1];
1206 Num_cloaking_walls--;
1209 else if (d->time > CLOAKING_WALL_TIME/2) {
1210 int old_type=wfront->type;
1212 wfront->cloak_value = ((d->time - CLOAKING_WALL_TIME/2) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1214 wback->cloak_value = wfront->cloak_value;
1216 if (old_type != WALL_CLOAKED) { //just switched
1219 wfront->type = WALL_CLOAKED;
1221 wback->type = WALL_CLOAKED;
1224 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1226 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1234 light_scale = fixdiv(CLOAKING_WALL_TIME/2-d->time,CLOAKING_WALL_TIME/2);
1237 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1239 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1243 if ( Newdemo_state == ND_STATE_RECORDING )
1244 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);
1248 void do_decloaking_wall_frame(int cloaking_wall_num)
1251 wall *wfront,*wback;
1253 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1255 d = &CloakingWalls[cloaking_wall_num];
1256 wfront = &Walls[d->front_wallnum];
1257 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1259 d->time += FrameTime;
1261 if (d->time > CLOAKING_WALL_TIME) {
1264 wfront->state = WALL_DOOR_CLOSED;
1266 wback->state = WALL_DOOR_CLOSED;
1269 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1271 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1274 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1275 CloakingWalls[i] = CloakingWalls[i+1];
1276 Num_cloaking_walls--;
1279 else if (d->time > CLOAKING_WALL_TIME/2) { //fading in
1283 wfront->type = wback->type = WALL_CLOSED;
1285 light_scale = fixdiv(d->time-CLOAKING_WALL_TIME/2,CLOAKING_WALL_TIME/2);
1288 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1290 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1293 else { //cloaking in
1294 wfront->cloak_value = ((CLOAKING_WALL_TIME/2 - d->time) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1295 wfront->type = WALL_CLOAKED;
1297 wback->cloak_value = wfront->cloak_value;
1298 wback->type = WALL_CLOAKED;
1302 if ( Newdemo_state == ND_STATE_RECORDING )
1303 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);
1307 void wall_frame_process()
1311 for (i=0;i<Num_open_doors;i++) {
1315 d = &ActiveDoors[i];
1316 w = &Walls[d->front_wallnum[0]];
1318 if (w->state == WALL_DOOR_OPENING)
1320 else if (w->state == WALL_DOOR_CLOSING)
1322 else if (w->state == WALL_DOOR_WAITING) {
1323 d->time += FrameTime;
1325 //set flags to fix occatsional netgame problem where door is
1326 //waiting to close but open flag isn't set
1327 Assert(d->n_parts == 1);
1328 w->flags |= WALL_DOOR_OPENED;
1329 if (d->back_wallnum[0] > -1)
1330 Walls[d->back_wallnum[0]].flags |= WALL_DOOR_OPENED;
1332 if (d->time > DOOR_WAIT_TIME && is_door_free(&Segments[w->segnum],w->sidenum)) {
1333 w->state = WALL_DOOR_CLOSING;
1337 else if (w->state == WALL_DOOR_CLOSED || w->state == WALL_DOOR_OPEN) {
1338 //this shouldn't happen. if the wall is in one of these states,
1339 //there shouldn't be an activedoor entry for it. So we'll kill
1340 //the activedoor entry. Tres simple.
1342 Int3(); //a bad thing has happened, but I'll try to fix it up
1343 for (t=i;t<Num_open_doors;t++)
1344 ActiveDoors[t] = ActiveDoors[t+1];
1349 for (i=0;i<Num_cloaking_walls;i++) {
1353 d = &CloakingWalls[i];
1354 w = &Walls[d->front_wallnum];
1356 if (w->state == WALL_DOOR_CLOAKING)
1357 do_cloaking_wall_frame(i);
1358 else if (w->state == WALL_DOOR_DECLOAKING)
1359 do_decloaking_wall_frame(i);
1362 Int3(); //unexpected wall state
1367 int Num_stuck_objects=0;
1369 stuckobj Stuck_objects[MAX_STUCK_OBJECTS];
1371 // An object got stuck in a door (like a flare).
1372 // Add global entry.
1373 void add_stuck_object(object *objp, int segnum, int sidenum)
1378 wallnum = Segments[segnum].sides[sidenum].wall_num;
1380 if (wallnum != -1) {
1381 if (Walls[wallnum].flags & WALL_BLASTED)
1382 objp->flags |= OF_SHOULD_BE_DEAD;
1384 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1385 if (Stuck_objects[i].wallnum == -1) {
1386 Stuck_objects[i].wallnum = wallnum;
1387 Stuck_objects[i].objnum = OBJECT_NUMBER(objp);
1388 Stuck_objects[i].signature = objp->signature;
1389 // mprintf((0, "Added wall %i at index %i\n", wallnum, i));
1390 Num_stuck_objects++;
1394 if (i == MAX_STUCK_OBJECTS)
1395 mprintf((1, "Warning: Unable to add object %i which got stuck in wall %i to Stuck_objects\n", OBJECT_NUMBER(objp), wallnum));
1402 // --------------------------------------------------------------------------------------------------
1403 // Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here.
1404 // Removes up to one/frame.
1405 void remove_obsolete_stuck_objects(void)
1409 // Safety and efficiency code. If no stuck objects, should never get inside the IF, but this is faster.
1410 if (!Num_stuck_objects)
1413 objnum = FrameCount % MAX_STUCK_OBJECTS;
1415 if (Stuck_objects[objnum].wallnum != -1)
1416 if ((Walls[Stuck_objects[objnum].wallnum].state != WALL_DOOR_CLOSED) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) {
1417 Num_stuck_objects--;
1418 Objects[Stuck_objects[objnum].objnum].lifeleft = F1_0/8;
1419 Stuck_objects[objnum].wallnum = -1;
1424 extern void flush_fcd_cache(void);
1426 // ----------------------------------------------------------------------------------------------------
1427 // Door with wall index wallnum is opening, kill all objects stuck in it.
1428 void kill_stuck_objects(int wallnum)
1432 if (wallnum < 0 || Num_stuck_objects == 0) {
1436 Num_stuck_objects=0;
1438 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1439 if (Stuck_objects[i].wallnum == wallnum) {
1440 if (Objects[Stuck_objects[i].objnum].type == OBJ_WEAPON) {
1441 Objects[Stuck_objects[i].objnum].lifeleft = F1_0/8;
1443 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));
1444 // Int3(); // What? This looks bad. Object is not a weapon and it is stuck in a wall!
1445 Stuck_objects[i].wallnum = -1;
1446 } else if (Stuck_objects[i].wallnum != -1) {
1447 Num_stuck_objects++;
1449 // Ok, this is awful, but we need to do things whenever a door opens/closes/disappears, etc.
1455 // -- unused -- // -----------------------------------------------------------------------------------
1456 // -- unused -- // Return object id of first flare found embedded in segp:sidenum.
1457 // -- unused -- // If no flare, return -1.
1458 // -- unused -- int contains_flare(segment *segp, int sidenum)
1460 // -- unused -- int i;
1462 // -- unused -- for (i=0; i<Num_stuck_objects; i++) {
1463 // -- unused -- object *objp = &Objects[Stuck_objects[i].objnum];
1465 // -- unused -- if ((objp->type == OBJ_WEAPON) && (objp->id == FLARE_ID)) {
1466 // -- unused -- if (Walls[Stuck_objects[i].wallnum].segnum == SEGMENT_NUMBER(segp))
1467 // -- unused -- if (Walls[Stuck_objects[i].wallnum].sidenum == sidenum)
1468 // -- unused -- return OBJECT_NUMBER(objp);
1472 // -- unused -- return -1;
1475 // -----------------------------------------------------------------------------------
1476 // Initialize stuck objects array. Called at start of level
1477 void init_stuck_objects(void)
1481 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1482 Stuck_objects[i].wallnum = -1;
1484 Num_stuck_objects = 0;
1487 // -----------------------------------------------------------------------------------
1488 // Clear out all stuck objects. Called for a new ship
1489 void clear_stuck_objects(void)
1493 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1494 if (Stuck_objects[i].wallnum != -1) {
1497 objnum = Stuck_objects[i].objnum;
1499 if ((Objects[objnum].type == OBJ_WEAPON) && (Objects[objnum].id == FLARE_ID))
1500 Objects[objnum].lifeleft = F1_0/8;
1502 Stuck_objects[i].wallnum = -1;
1504 Num_stuck_objects--;
1508 Assert(Num_stuck_objects == 0);
1512 // -----------------------------------------------------------------------------------
1513 #define MAX_BLAST_GLASS_DEPTH 5
1515 void bng_process_segment(object *objp, fix damage, segment *segp, int depth, sbyte *visited)
1519 if (depth > MAX_BLAST_GLASS_DEPTH)
1524 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1529 // Process only walls which have glass.
1530 if ((tm=segp->sides[sidenum].tmap_num2) != 0) {
1533 tm &= 0x3fff; //tm without flags
1535 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))) {
1536 compute_center_point_on_side(&pnt, segp, sidenum);
1537 dist = vm_vec_dist_quick(&pnt, &objp->pos);
1538 if (dist < damage/2) {
1539 dist = find_connected_distance(&pnt, SEGMENT_NUMBER(segp), &objp->pos, objp->segnum, MAX_BLAST_GLASS_DEPTH, WID_RENDPAST_FLAG);
1540 if ((dist > 0) && (dist < damage/2))
1541 check_effect_blowup(segp, sidenum, &pnt, &Objects[objp->ctype.laser_info.parent_num], 1);
1547 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1548 int segnum = segp->children[i];
1551 if (!visited[segnum]) {
1552 if (WALL_IS_DOORWAY(segp, i) & WID_FLY_FLAG) {
1553 visited[segnum] = 1;
1554 bng_process_segment(objp, damage, &Segments[segnum], depth, visited);
1561 // -----------------------------------------------------------------------------------
1562 // objp is going to detonate
1563 // blast nearby monitors, lights, maybe other things
1564 void blast_nearby_glass(object *objp, fix damage)
1567 sbyte visited[MAX_SEGMENTS];
1570 cursegp = &Segments[objp->segnum];
1571 for (i=0; i<=Highest_segment_index; i++)
1574 visited[objp->segnum] = 1;
1575 bng_process_segment(objp, damage, cursegp, 0, visited);
1580 #define MAX_CLIP_FRAMES_D1 20
1583 * reads a wclip structure from a CFILE
1585 int wclip_read_n_d1(wclip *wc, int n, CFILE *fp)
1589 for (i = 0; i < n; i++) {
1590 wc[i].play_time = cfile_read_fix(fp);
1591 wc[i].num_frames = cfile_read_short(fp);
1592 for (j = 0; j < MAX_CLIP_FRAMES_D1; j++)
1593 wc[i].frames[j] = cfile_read_short(fp);
1594 wc[i].open_sound = cfile_read_short(fp);
1595 wc[i].close_sound = cfile_read_short(fp);
1596 wc[i].flags = cfile_read_short(fp);
1597 cfread(wc[i].filename, 13, 1, fp);
1598 wc[i].pad = cfile_read_byte(fp);
1603 #ifndef FAST_FILE_IO
1605 * reads a wclip structure from a CFILE
1607 int wclip_read_n(wclip *wc, int n, CFILE *fp)
1611 for (i = 0; i < n; i++) {
1612 wc[i].play_time = cfile_read_fix(fp);
1613 wc[i].num_frames = cfile_read_short(fp);
1614 for (j = 0; j < MAX_CLIP_FRAMES; j++)
1615 wc[i].frames[j] = cfile_read_short(fp);
1616 wc[i].open_sound = cfile_read_short(fp);
1617 wc[i].close_sound = cfile_read_short(fp);
1618 wc[i].flags = cfile_read_short(fp);
1619 cfread(wc[i].filename, 13, 1, fp);
1620 wc[i].pad = cfile_read_byte(fp);
1626 * reads a v16_wall structure from a CFILE
1628 extern void v16_wall_read(v16_wall *w, CFILE *fp)
1630 w->type = cfile_read_byte(fp);
1631 w->flags = cfile_read_byte(fp);
1632 w->hps = cfile_read_fix(fp);
1633 w->trigger = cfile_read_byte(fp);
1634 w->clip_num = cfile_read_byte(fp);
1635 w->keys = cfile_read_byte(fp);
1639 * reads a v19_wall structure from a CFILE
1641 extern void v19_wall_read(v19_wall *w, CFILE *fp)
1643 w->segnum = cfile_read_int(fp);
1644 w->sidenum = cfile_read_int(fp);
1645 w->type = cfile_read_byte(fp);
1646 w->flags = cfile_read_byte(fp);
1647 w->hps = cfile_read_fix(fp);
1648 w->trigger = cfile_read_byte(fp);
1649 w->clip_num = cfile_read_byte(fp);
1650 w->keys = cfile_read_byte(fp);
1651 w->linked_wall = cfile_read_int(fp);
1655 * reads a wall structure from a CFILE
1657 extern void wall_read(wall *w, CFILE *fp)
1659 w->segnum = cfile_read_int(fp);
1660 w->sidenum = cfile_read_int(fp);
1661 w->hps = cfile_read_fix(fp);
1662 w->linked_wall = cfile_read_int(fp);
1663 w->type = cfile_read_byte(fp);
1664 w->flags = cfile_read_byte(fp);
1665 w->state = cfile_read_byte(fp);
1666 w->trigger = cfile_read_byte(fp);
1667 w->clip_num = cfile_read_byte(fp);
1668 w->keys = cfile_read_byte(fp);
1669 w->controlling_trigger = cfile_read_byte(fp);
1670 w->cloak_value = cfile_read_byte(fp);
1674 * reads a v19_door structure from a CFILE
1676 extern void v19_door_read(v19_door *d, CFILE *fp)
1678 d->n_parts = cfile_read_int(fp);
1679 d->seg[0] = cfile_read_short(fp);
1680 d->seg[1] = cfile_read_short(fp);
1681 d->side[0] = cfile_read_short(fp);
1682 d->side[1] = cfile_read_short(fp);
1683 d->type[0] = cfile_read_short(fp);
1684 d->type[1] = cfile_read_short(fp);
1685 d->open = cfile_read_fix(fp);
1689 * reads an active_door structure from a CFILE
1691 extern void active_door_read(active_door *ad, CFILE *fp)
1693 ad->n_parts = cfile_read_int(fp);
1694 ad->front_wallnum[0] = cfile_read_short(fp);
1695 ad->front_wallnum[1] = cfile_read_short(fp);
1696 ad->back_wallnum[0] = cfile_read_short(fp);
1697 ad->back_wallnum[1] = cfile_read_short(fp);
1698 ad->time = cfile_read_fix(fp);
1702 void wall_write(wall *w, short version, CFILE *fp)
1706 PHYSFS_writeSLE32(fp, w->segnum);
1707 PHYSFS_writeSLE32(fp, w->sidenum);
1712 PHYSFSX_writeFix(fp, w->hps);
1713 PHYSFS_writeSLE32(fp, w->linked_wall);
1716 PHYSFSX_writeU8(fp, w->type);
1717 PHYSFSX_writeU8(fp, w->flags);
1720 PHYSFSX_writeFix(fp, w->hps);
1722 PHYSFSX_writeU8(fp, w->state);
1724 PHYSFSX_writeU8(fp, w->trigger);
1725 PHYSFSX_writeU8(fp, w->clip_num);
1726 PHYSFSX_writeU8(fp, w->keys);
1730 PHYSFSX_writeU8(fp, w->controlling_trigger);
1731 PHYSFSX_writeU8(fp, w->cloak_value);
1733 else if (version >= 17)
1734 PHYSFS_writeSLE32(fp, w->linked_wall);