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
34 #include "editor/editor.h"
38 // Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK.
39 #define BOSS_LOCKED_DOOR_LEVEL 7
40 #define BOSS_LOCKED_DOOR_SEG 595
41 #define BOSS_LOCKED_DOOR_SIDE 5
43 wall Walls[MAX_WALLS]; // Master walls array
44 int Num_walls=0; // Number of walls
46 wclip WallAnims[MAX_WALL_ANIMS]; // Wall animations
48 //--unused-- int walls_bm_num[MAX_WALL_ANIMS];
50 //door Doors[MAX_DOORS]; // Master doors array
52 active_door ActiveDoors[MAX_DOORS];
53 int Num_open_doors; // Number of open doors
55 #define CLOAKING_WALL_TIME f1_0
57 #define MAX_CLOAKING_WALLS 10
58 cloaking_wall CloakingWalls[MAX_CLOAKING_WALLS];
59 int Num_cloaking_walls;
61 //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS];
63 //#define BM_FLAG_TRANSPARENT 1
64 //#define BM_FLAG_SUPER_TRANSPARENT 2
67 char Wall_names[7][10] = {
78 // Function prototypes
79 void kill_stuck_objects(int wallnum);
83 // This function determines whether the current segment/side is transparent
86 int check_transparency( segment * seg, int side )
88 if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) {
89 if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT )
95 if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT )
101 //-----------------------------------------------------------------
102 // This function checks whether we can fly through the given side.
103 // In other words, whether or not we have a 'doorway'
107 // WID_RENDPAST_FLAG 4
109 // WID_WALL 2 // 0/1/0 wall
110 // WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
111 // WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
112 // WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
113 // WID_NO_WALL 5 // 1/0/1 no wall, can fly through
114 int wall_is_doorway ( segment * seg, int side )
118 //--Covered by macro // No child.
119 //--Covered by macro if (seg->children[side] == -1)
120 //--Covered by macro return WID_WALL;
122 //--Covered by macro if (seg->children[side] == -2)
123 //--Covered by macro return WID_EXTERNAL_FLAG;
125 //--Covered by macro // No wall present.
126 //--Covered by macro if (seg->sides[side].wall_num == -1)
127 //--Covered by macro return WID_NO_WALL;
129 Assert(SEGMENT_NUMBER(seg) >= 0 && SEGMENT_NUMBER(seg) <= Highest_segment_index);
130 Assert(side>=0 && side<6);
132 type = Walls[seg->sides[side].wall_num].type;
133 flags = Walls[seg->sides[side].wall_num].flags;
135 if (type == WALL_OPEN)
138 if (type == WALL_ILLUSION) {
139 if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF)
142 if (check_transparency( seg, side))
143 return WID_TRANSILLUSORY_WALL;
145 return WID_ILLUSORY_WALL;
149 if (type == WALL_BLASTABLE) {
150 if (flags & WALL_BLASTED)
151 return WID_TRANSILLUSORY_WALL;
153 if (check_transparency( seg, side))
154 return WID_TRANSPARENT_WALL;
159 if (flags & WALL_DOOR_OPENED)
160 return WID_TRANSILLUSORY_WALL;
162 if (type == WALL_CLOAKED)
163 return WID_RENDER_FLAG | WID_RENDPAST_FLAG | WID_CLOAKED_FLAG;
165 state = Walls[seg->sides[side].wall_num].state;
166 if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING))
167 return WID_TRANSPARENT_WALL;
169 // If none of the above flags are set, there is no doorway.
170 if (check_transparency( seg, side))
171 return WID_TRANSPARENT_WALL;
173 return WID_WALL; // There are children behind the door.
177 //-----------------------------------------------------------------
178 // Initializes all the walls (in other words, no special walls)
184 for (i=0;i<MAX_WALLS;i++) {
185 Walls[i].segnum = Walls[i].sidenum = -1;
186 Walls[i].type = WALL_NORMAL;
189 Walls[i].trigger = -1;
190 Walls[i].clip_num = -1;
191 Walls[i].linked_wall = -1;
194 Num_cloaking_walls = 0;
198 //-----------------------------------------------------------------
199 // Initializes one wall.
200 void wall_reset(segment *seg, int side)
204 i = seg->sides[side].wall_num;
207 mprintf((0, "Resetting Illegal Wall\n"));
211 Walls[i].segnum = SEGMENT_NUMBER(seg);
212 Walls[i].sidenum = side;
213 Walls[i].type = WALL_NORMAL;
216 Walls[i].trigger = -1;
217 Walls[i].clip_num = -1;
218 Walls[i].linked_wall = -1;
222 //set the tmap_num or tmap_num2 field for a wall/door
223 void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num)
225 wclip *anim = &WallAnims[anim_num];
226 int tmap = anim->frames[frame_num];
228 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
230 if (anim->flags & WCF_TMAP1) {
231 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap;
232 if ( Newdemo_state == ND_STATE_RECORDING )
233 newdemo_record_wall_set_tmap_num1(SEGMENT_NUMBER(seg), side, SEGMENT_NUMBER(csegp), cside, tmap);
235 Assert(tmap!=0 && seg->sides[side].tmap_num2!=0);
236 seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap;
237 if ( Newdemo_state == ND_STATE_RECORDING )
238 newdemo_record_wall_set_tmap_num2(SEGMENT_NUMBER(seg), side, SEGMENT_NUMBER(csegp), cside, tmap);
243 // -------------------------------------------------------------------------------
244 //when the wall has used all its hitpoints, this will destroy it
245 void blast_blastable_wall(segment *seg, int side)
251 Assert(seg->sides[side].wall_num != -1);
253 Walls[seg->sides[side].wall_num].hps = -1; //say it's blasted
255 csegp = &Segments[seg->children[side]];
256 Connectside = find_connect_side(seg, csegp);
257 Assert(Connectside != -1);
258 cwall_num = csegp->sides[Connectside].wall_num;
259 kill_stuck_objects(seg->sides[side].wall_num);
261 kill_stuck_objects(cwall_num);
263 //if this is an exploding wall, explode it
264 if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES)
265 explode_wall(SEGMENT_NUMBER(seg), side);
267 //if not exploding, set final frame, and make door passable
268 a = Walls[seg->sides[side].wall_num].clip_num;
269 n = WallAnims[a].num_frames;
270 wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1);
271 Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED;
273 Walls[cwall_num].flags |= WALL_BLASTED;
279 //-----------------------------------------------------------------
280 // Destroys a blastable wall.
281 void wall_destroy(segment *seg, int side)
283 Assert(seg->sides[side].wall_num != -1);
284 Assert(SEGMENT_NUMBER(seg) != 0);
286 if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
287 blast_blastable_wall( seg, side );
289 Error("Hey bub, you are trying to destroy an indestructable wall.");
292 //-----------------------------------------------------------------
293 // Deteriorate appearance of wall. (Changes bitmap (paste-ons))
294 void wall_damage(segment *seg, int side, fix damage)
296 int a, i, n, cwall_num;
298 if (seg->sides[side].wall_num == -1) {
299 mprintf((0, "Damaging illegal wall\n"));
303 if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE)
306 if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED) && Walls[seg->sides[side].wall_num].hps >= 0)
311 csegp = &Segments[seg->children[side]];
312 Connectside = find_connect_side(seg, csegp);
313 Assert(Connectside != -1);
314 cwall_num = csegp->sides[Connectside].wall_num;
315 Walls[seg->sides[side].wall_num].hps -= damage;
317 Walls[cwall_num].hps -= damage;
319 a = Walls[seg->sides[side].wall_num].clip_num;
320 n = WallAnims[a].num_frames;
322 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) {
323 blast_blastable_wall( seg, side );
325 if (Game_mode & GM_MULTI)
326 multi_send_door_open(SEGMENT_NUMBER(seg), side, Walls[seg->sides[side].wall_num].flags);
331 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*(n-i)/n) {
332 wall_set_tmap_num(seg,side,csegp,Connectside,a,i);
338 //-----------------------------------------------------------------
340 void wall_open_door(segment *seg, int side)
344 int Connectside, cwall_num;
347 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
349 w = &Walls[seg->sides[side].wall_num];
350 //kill_stuck_objects(seg->sides[side].wall_num);
352 if ((w->state == WALL_DOOR_OPENING) || //already opening
353 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
354 (w->state == WALL_DOOR_OPEN)) //open, & staying open
357 if (w->state == WALL_DOOR_CLOSING) { //closing, so reuse door
363 for (i=0;i<Num_open_doors;i++) { //find door
367 if (d->front_wallnum[0] == WALL_NUMBER(w) ||
368 d->back_wallnum[0] == WALL_NUMBER(w) ||
369 (d->n_parts == 2 && (d->front_wallnum[1] == WALL_NUMBER(w) ||
370 d->back_wallnum[1] == WALL_NUMBER(w))))
374 if (i>=Num_open_doors && (Game_mode & GM_MULTI))
377 Assert(i<Num_open_doors); //didn't find door!
378 Assert( d!=NULL ); // Get John!
380 d->time = WallAnims[w->clip_num].play_time - d->time;
386 else { //create new door
387 Assert(w->state == WALL_DOOR_CLOSED);
389 d = &ActiveDoors[Num_open_doors];
392 Assert( Num_open_doors < MAX_DOORS );
396 w->state = WALL_DOOR_OPENING;
398 // So that door can't be shot while opening
399 csegp = &Segments[seg->children[side]];
400 Connectside = find_connect_side(seg, csegp);
401 Assert(Connectside != -1);
402 cwall_num = csegp->sides[Connectside].wall_num;
404 Walls[cwall_num].state = WALL_DOOR_OPENING;
406 //kill_stuck_objects(csegp->sides[Connectside].wall_num);
408 d->front_wallnum[0] = seg->sides[side].wall_num;
409 d->back_wallnum[0] = cwall_num;
411 Assert( SEGMENT_NUMBER(seg) != -1 );
413 if (Newdemo_state == ND_STATE_RECORDING) {
414 newdemo_record_door_opening(SEGMENT_NUMBER(seg), side);
417 if (w->linked_wall != -1) {
421 w2 = &Walls[w->linked_wall];
422 seg2 = &Segments[w2->segnum];
424 Assert(w2->linked_wall == seg->sides[side].wall_num);
425 //Assert(!(w2->flags & WALL_DOOR_OPENING || w2->flags & WALL_DOOR_OPENED));
427 w2->state = WALL_DOOR_OPENING;
429 csegp = &Segments[seg2->children[w2->sidenum]];
430 Connectside = find_connect_side(seg2, csegp);
431 Assert(Connectside != -1);
433 Walls[cwall_num].state = WALL_DOOR_OPENING;
436 d->front_wallnum[1] = w->linked_wall;
437 d->back_wallnum[1] = cwall_num;
443 if ( Newdemo_state != ND_STATE_PLAYBACK )
445 // NOTE THE LINK TO ABOVE!!!!
447 compute_center_point_on_side(&cp, seg, side );
448 if (WallAnims[w->clip_num].open_sound > -1 )
449 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
454 //-----------------------------------------------------------------
455 // start the transition from closed -> open wall
456 void start_wall_cloak(segment *seg, int side)
464 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
466 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
468 w = &Walls[seg->sides[side].wall_num];
470 if (w->type == WALL_OPEN || w->state == WALL_DOOR_CLOAKING) //already open or cloaking
473 csegp = &Segments[seg->children[side]];
474 Connectside = find_connect_side(seg, csegp);
475 Assert(Connectside != -1);
476 cwall_num = csegp->sides[Connectside].wall_num;
478 if (w->state == WALL_DOOR_DECLOAKING) { //decloaking, so reuse door
484 for (i=0;i<Num_cloaking_walls;i++) { //find door
486 d = &CloakingWalls[i];
488 if (d->front_wallnum == WALL_NUMBER(w) || d->back_wallnum == WALL_NUMBER(w))
492 Assert(i<Num_cloaking_walls); //didn't find door!
493 Assert( d!=NULL ); // Get John!
495 d->time = CLOAKING_WALL_TIME - d->time;
498 else if (w->state == WALL_DOOR_CLOSED) { //create new door
499 d = &CloakingWalls[Num_cloaking_walls];
501 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
502 Int3(); //ran out of cloaking wall slots
505 Walls[cwall_num].type = WALL_OPEN;
508 Num_cloaking_walls++;
511 Int3(); //unexpected wall state
515 w->state = WALL_DOOR_CLOAKING;
517 Walls[cwall_num].state = WALL_DOOR_CLOAKING;
519 d->front_wallnum = seg->sides[side].wall_num;
520 d->back_wallnum = cwall_num;
522 Assert( SEGMENT_NUMBER(seg) != -1 );
524 Assert(w->linked_wall == -1);
526 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
528 compute_center_point_on_side(&cp, seg, side );
529 digi_link_sound_to_pos( SOUND_WALL_CLOAK_ON, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
533 d->front_ls[i] = seg->sides[side].uvls[i].l;
535 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
539 //-----------------------------------------------------------------
540 // start the transition from open -> closed wall
541 void start_wall_decloak(segment *seg, int side)
549 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
551 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
553 w = &Walls[seg->sides[side].wall_num];
555 if (w->type == WALL_CLOSED || w->state == WALL_DOOR_DECLOAKING) //already closed or decloaking
558 if (w->state == WALL_DOOR_CLOAKING) { //cloaking, so reuse door
564 for (i=0;i<Num_cloaking_walls;i++) { //find door
566 d = &CloakingWalls[i];
568 if (d->front_wallnum == WALL_NUMBER(w) || d->back_wallnum == WALL_NUMBER(w))
572 Assert(i<Num_cloaking_walls); //didn't find door!
573 Assert( d!=NULL ); // Get John!
575 d->time = CLOAKING_WALL_TIME - d->time;
578 else if (w->state == WALL_DOOR_CLOSED) { //create new door
579 d = &CloakingWalls[Num_cloaking_walls];
581 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
582 Int3(); //ran out of cloaking wall slots
583 /* what is this _doing_ here?
584 w->type = WALL_CLOSED;
585 Walls[csegp->sides[Connectside].wall_num].type = WALL_CLOSED;
589 Num_cloaking_walls++;
592 Int3(); //unexpected wall state
596 w->state = WALL_DOOR_DECLOAKING;
598 // So that door can't be shot while opening
599 csegp = &Segments[seg->children[side]];
600 Connectside = find_connect_side(seg, csegp);
601 Assert(Connectside != -1);
602 cwall_num = csegp->sides[Connectside].wall_num;
604 Walls[cwall_num].state = WALL_DOOR_DECLOAKING;
606 d->front_wallnum = seg->sides[side].wall_num;
607 d->back_wallnum = csegp->sides[Connectside].wall_num;
609 Assert( SEGMENT_NUMBER(seg) != -1 );
611 Assert(w->linked_wall == -1);
613 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
615 compute_center_point_on_side(&cp, seg, side );
616 digi_link_sound_to_pos( SOUND_WALL_CLOAK_OFF, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
620 d->front_ls[i] = seg->sides[side].uvls[i].l;
622 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
626 //-----------------------------------------------------------------
627 // This function closes the specified door and restores the closed
628 // door texture. This is called when the animation is done
629 void wall_close_door_num(int door_num)
635 d = &ActiveDoors[door_num];
637 for (p=0;p<d->n_parts;p++) {
639 int Connectside, side;
640 segment *csegp, *seg;
642 w = &Walls[d->front_wallnum[p]];
644 seg = &Segments[w->segnum];
647 Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall
649 csegp = &Segments[seg->children[side]];
650 Connectside = find_connect_side(seg, csegp);
651 Assert(Connectside != -1);
652 cwall_num = csegp->sides[Connectside].wall_num;
653 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED;
655 Walls[cwall_num].state = WALL_DOOR_CLOSED;
657 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0);
661 for (i=door_num;i<Num_open_doors;i++)
662 ActiveDoors[i] = ActiveDoors[i+1];
668 int check_poke(int objnum,int segnum,int side)
670 object *obj = &Objects[objnum];
672 //note: don't let objects with zero size block door
674 if (obj->size && get_seg_masks(&obj->pos, segnum, obj->size, __FILE__, __LINE__).sidemask & (1 << side))
675 return 1; //pokes through side!
677 return 0; //does not!
681 //returns true of door in unobjstructed (& thus can close)
682 int is_door_free(segment *seg,int side)
688 csegp = &Segments[seg->children[side]];
689 Connectside = find_connect_side(seg, csegp);
690 Assert(Connectside != -1);
692 //go through each object in each of two segments, and see if
693 //it pokes into the connecting seg
695 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
696 if (Objects[objnum].type != OBJ_WEAPON && Objects[objnum].type != OBJ_FIREBALL && check_poke(objnum, SEGMENT_NUMBER(seg), side))
699 for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next)
700 if (Objects[objnum].type != OBJ_WEAPON && Objects[objnum].type != OBJ_FIREBALL && check_poke(objnum, SEGMENT_NUMBER(csegp), Connectside))
703 return 1; //doorway is free!
708 //-----------------------------------------------------------------
710 void wall_close_door(segment *seg, int side)
714 int Connectside, cwall_num;
717 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
719 w = &Walls[seg->sides[side].wall_num];
721 if ((w->state == WALL_DOOR_CLOSING) || //already closing
722 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
723 (w->state == WALL_DOOR_CLOSED)) //closed
726 if (!is_door_free(seg,side))
729 if (w->state == WALL_DOOR_OPENING) { //reuse door
735 for (i=0;i<Num_open_doors;i++) { //find door
739 if (d->front_wallnum[0] == WALL_NUMBER(w) ||
740 d->back_wallnum[0] == WALL_NUMBER(w) ||
741 (d->n_parts == 2 && (d->front_wallnum[1] == WALL_NUMBER(w) ||
742 d->back_wallnum[1] == WALL_NUMBER(w))))
746 Assert(i<Num_open_doors); //didn't find door!
747 Assert( d!=NULL ); // Get John!
749 d->time = WallAnims[w->clip_num].play_time - d->time;
755 else { //create new door
756 Assert(w->state == WALL_DOOR_OPEN);
757 d = &ActiveDoors[Num_open_doors];
760 Assert( Num_open_doors < MAX_DOORS );
763 w->state = WALL_DOOR_CLOSING;
765 // So that door can't be shot while opening
766 csegp = &Segments[seg->children[side]];
767 Connectside = find_connect_side(seg, csegp);
768 Assert(Connectside != -1);
769 cwall_num = csegp->sides[Connectside].wall_num;
771 Walls[cwall_num].state = WALL_DOOR_CLOSING;
773 d->front_wallnum[0] = seg->sides[side].wall_num;
774 d->back_wallnum[0] = cwall_num;
776 Assert( SEGMENT_NUMBER(seg) != -1 );
778 if (Newdemo_state == ND_STATE_RECORDING) {
779 newdemo_record_door_opening(SEGMENT_NUMBER(seg), side);
782 if (w->linked_wall != -1) {
783 Int3(); //don't think we ever used linked walls
789 if ( Newdemo_state != ND_STATE_PLAYBACK )
791 // NOTE THE LINK TO ABOVE!!!!
793 compute_center_point_on_side(&cp, seg, side );
794 if (WallAnims[w->clip_num].open_sound > -1 )
795 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
800 //-----------------------------------------------------------------
801 // Animates opening of a door.
802 // Called in the game loop.
803 void do_door_open(int door_num)
808 Assert(door_num != -1); //Trying to do_door_open on illegal door
810 d = &ActiveDoors[door_num];
812 for (p=0;p<d->n_parts;p++) {
814 int Connectside, side;
815 segment *csegp, *seg;
816 fix time_elapsed, time_total, one_frame;
819 w = &Walls[d->front_wallnum[p]];
820 kill_stuck_objects(d->front_wallnum[p]);
821 kill_stuck_objects(d->back_wallnum[p]);
823 seg = &Segments[w->segnum];
826 Assert(seg->sides[side].wall_num != -1); //Trying to do_door_open on illegal wall
828 csegp = &Segments[seg->children[side]];
829 Connectside = find_connect_side(seg, csegp);
830 Assert(Connectside != -1);
832 d->time += FrameTime;
834 time_elapsed = d->time;
835 n = WallAnims[w->clip_num].num_frames;
836 time_total = WallAnims[w->clip_num].play_time;
838 one_frame = time_total/n;
840 i = time_elapsed/one_frame;
843 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
846 Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED;
847 Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED;
851 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1);
853 // If our door is not automatic just remove it from the list.
854 if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) {
855 for (i=door_num;i<Num_open_doors;i++)
856 ActiveDoors[i] = ActiveDoors[i+1];
858 Walls[seg->sides[side].wall_num].state = WALL_DOOR_OPEN;
859 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPEN;
863 Walls[seg->sides[side].wall_num].state = WALL_DOOR_WAITING;
864 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING;
866 ActiveDoors[Num_open_doors].time = 0; //counts up
874 //-----------------------------------------------------------------
875 // Animates and processes the closing of a door.
876 // Called from the game loop.
877 void do_door_close(int door_num)
883 Assert(door_num != -1); //Trying to do_door_open on illegal door
885 d = &ActiveDoors[door_num];
887 w = &Walls[d->front_wallnum[0]];
889 //check for objects in doorway before closing
890 if (w->flags & WALL_DOOR_AUTO)
891 if (!is_door_free(&Segments[w->segnum],w->sidenum)) {
892 digi_kill_sound_linked_to_segment(w->segnum,w->sidenum,-1);
893 wall_open_door(&Segments[w->segnum],w->sidenum); //re-open door
897 for (p=0;p<d->n_parts;p++) {
899 int Connectside, side;
900 segment *csegp, *seg;
901 fix time_elapsed, time_total, one_frame;
904 w = &Walls[d->front_wallnum[p]];
906 seg = &Segments[w->segnum];
909 if (seg->sides[side].wall_num == -1) {
910 mprintf((0, "Trying to do_door_close on Illegal wall\n"));
914 //if here, must be auto door
915 // Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO);
916 //don't assert here, because now we have triggers to close non-auto doors
918 // Otherwise, close it.
919 csegp = &Segments[seg->children[side]];
920 Connectside = find_connect_side(seg, csegp);
921 Assert(Connectside != -1);
924 if ( Newdemo_state != ND_STATE_PLAYBACK )
925 // NOTE THE LINK TO ABOVE!!
926 if (p==0) //only play one sound for linked doors
927 if ( d->time==0 ) { //first time
929 compute_center_point_on_side(&cp, seg, side );
930 if (WallAnims[w->clip_num].close_sound > -1 )
931 digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, SEGMENT_NUMBER(seg), side, &cp, 0, F1_0 );
934 d->time += FrameTime;
936 time_elapsed = d->time;
937 n = WallAnims[w->clip_num].num_frames;
938 time_total = WallAnims[w->clip_num].play_time;
940 one_frame = time_total/n;
942 i = n-time_elapsed/one_frame-1;
945 Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED;
946 Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED;
951 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
953 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING;
954 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
956 ActiveDoors[Num_open_doors].time = 0; //counts up
959 wall_close_door_num(door_num);
964 //-----------------------------------------------------------------
965 // Turns off an illusionary wall (This will be used primarily for
966 // wall switches or triggers that can turn on/off illusionary walls.)
967 void wall_illusion_off(segment *seg, int side)
972 csegp = &Segments[seg->children[side]];
973 cside = find_connect_side(seg, csegp);
976 if (seg->sides[side].wall_num == -1) {
977 mprintf((0, "Trying to shut off illusion illegal wall\n"));
981 Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF;
982 Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF;
984 kill_stuck_objects(seg->sides[side].wall_num);
985 kill_stuck_objects(csegp->sides[cside].wall_num);
988 //-----------------------------------------------------------------
989 // Turns on an illusionary wall (This will be used primarily for
990 // wall switches or triggers that can turn on/off illusionary walls.)
991 void wall_illusion_on(segment *seg, int side)
996 csegp = &Segments[seg->children[side]];
997 cside = find_connect_side(seg, csegp);
1000 if (seg->sides[side].wall_num == -1) {
1001 mprintf((0, "Trying to turn on illusion illegal wall\n"));
1005 Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF;
1006 Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF;
1009 // -----------------------------------------------------------------------------
1010 // Allowed to open the normally locked special boss door if in multiplayer mode.
1011 int special_boss_opening_allowed(int segnum, int sidenum)
1013 if (Game_mode & GM_MULTI)
1014 return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE);
1019 //-----------------------------------------------------------------
1020 // Determines what happens when a wall is shot
1021 //returns info about wall. see wall.h for codes
1022 //obj is the object that hit...either a weapon or the player himself
1023 //playernum is the number the player who hit the wall or fired the weapon,
1024 //or -1 if a robot fired the weapon
1025 int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj )
1030 Assert( SEGMENT_NUMBER(seg) != -1 );
1032 // If it is not a "wall" then just return.
1033 if ( seg->sides[side].wall_num < 0 )
1034 return WHP_NOT_SPECIAL;
1036 w = &Walls[seg->sides[side].wall_num];
1038 if ( Newdemo_state == ND_STATE_RECORDING )
1039 newdemo_record_wall_hit_process( SEGMENT_NUMBER(seg), side, damage, playernum );
1041 if (w->type == WALL_BLASTABLE) {
1042 if (obj->ctype.laser_info.parent_type == OBJ_PLAYER)
1043 wall_damage(seg, side, damage);
1044 return WHP_BLASTABLE;
1047 if (playernum != Player_num) //return if was robot fire
1048 return WHP_NOT_SPECIAL;
1050 Assert( playernum > -1 );
1052 // Determine whether player is moving forward. If not, don't say negative
1053 // messages because he probably didn't intentionally hit the door.
1054 if (obj->type == OBJ_PLAYER)
1055 show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0);
1056 else if (obj->type == OBJ_ROBOT)
1058 else if ((obj->type == OBJ_WEAPON) && (obj->ctype.laser_info.parent_type == OBJ_ROBOT))
1063 if (w->keys == KEY_BLUE)
1064 if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) {
1065 if ( playernum==Player_num )
1067 HUD_init_message("%s %s",TXT_BLUE,TXT_ACCESS_DENIED);
1071 if (w->keys == KEY_RED)
1072 if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) {
1073 if ( playernum==Player_num )
1075 HUD_init_message("%s %s",TXT_RED,TXT_ACCESS_DENIED);
1079 if (w->keys == KEY_GOLD)
1080 if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) {
1081 if ( playernum==Player_num )
1083 HUD_init_message("%s %s",TXT_YELLOW,TXT_ACCESS_DENIED);
1087 if (w->type == WALL_DOOR)
1089 if ( (w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(SEGMENT_NUMBER(seg), side)) ) {
1090 if ( playernum==Player_num )
1092 HUD_init_message(TXT_CANT_OPEN_DOOR);
1096 if (w->state != WALL_DOOR_OPENING)
1098 wall_open_door(seg, side);
1100 if (Game_mode & GM_MULTI)
1101 multi_send_door_open(SEGMENT_NUMBER(seg), side, w->flags);
1109 return WHP_NOT_SPECIAL; //default is treat like normal wall
1112 //-----------------------------------------------------------------
1113 // Opens doors/destroys wall/shuts off triggers.
1114 void wall_toggle(segment *seg, int side)
1118 if (SEGMENT_NUMBER(seg) > Highest_segment_index)
1120 Warning("Can't toggle side %d of segment %d - nonexistent segment!\n", side, SEGMENT_NUMBER(seg));
1123 Assert( side < MAX_SIDES_PER_SEGMENT );
1125 wall_num = seg->sides[side].wall_num;
1127 if (wall_num == -1) {
1128 mprintf((0, "Illegal wall_toggle\n"));
1132 if ( Newdemo_state == ND_STATE_RECORDING )
1133 newdemo_record_wall_toggle( SEGMENT_NUMBER(seg), side );
1135 if (Walls[wall_num].type == WALL_BLASTABLE)
1136 wall_destroy(seg, side);
1138 if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED))
1139 wall_open_door(seg, side);
1144 //-----------------------------------------------------------------
1145 // Tidy up Walls array for load/save purposes.
1150 if (Num_walls < 0) {
1151 mprintf((0, "Illegal Num_walls\n"));
1155 for (i=Num_walls;i<MAX_WALLS;i++) {
1156 Walls[i].type = WALL_NORMAL;
1159 Walls[i].trigger = -1;
1160 Walls[i].clip_num = -1;
1164 void do_cloaking_wall_frame(int cloaking_wall_num)
1167 wall *wfront,*wback;
1169 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1171 d = &CloakingWalls[cloaking_wall_num];
1172 wfront = &Walls[d->front_wallnum];
1173 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1175 d->time += FrameTime;
1177 if (d->time > CLOAKING_WALL_TIME) {
1180 wfront->type = WALL_OPEN;
1181 wfront->state = WALL_DOOR_CLOSED; //why closed? why not?
1183 wback->type = WALL_OPEN;
1184 wback->state = WALL_DOOR_CLOSED; //why closed? why not?
1187 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1188 CloakingWalls[i] = CloakingWalls[i+1];
1189 Num_cloaking_walls--;
1192 else if (d->time > CLOAKING_WALL_TIME/2) {
1193 int old_type=wfront->type;
1195 wfront->cloak_value = ((d->time - CLOAKING_WALL_TIME/2) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1197 wback->cloak_value = wfront->cloak_value;
1199 if (old_type != WALL_CLOAKED) { //just switched
1202 wfront->type = WALL_CLOAKED;
1204 wback->type = WALL_CLOAKED;
1207 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1209 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1217 light_scale = fixdiv(CLOAKING_WALL_TIME/2-d->time,CLOAKING_WALL_TIME/2);
1220 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 = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1242 d->time += FrameTime;
1244 if (d->time > CLOAKING_WALL_TIME) {
1247 wfront->state = WALL_DOOR_CLOSED;
1249 wback->state = WALL_DOOR_CLOSED;
1252 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1254 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1257 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1258 CloakingWalls[i] = CloakingWalls[i+1];
1259 Num_cloaking_walls--;
1262 else if (d->time > CLOAKING_WALL_TIME/2) { //fading in
1266 wfront->type = wback->type = WALL_CLOSED;
1268 light_scale = fixdiv(d->time-CLOAKING_WALL_TIME/2,CLOAKING_WALL_TIME/2);
1271 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1273 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1276 else { //cloaking in
1277 wfront->cloak_value = ((CLOAKING_WALL_TIME/2 - d->time) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1278 wfront->type = WALL_CLOAKED;
1280 wback->cloak_value = wfront->cloak_value;
1281 wback->type = WALL_CLOAKED;
1285 if ( Newdemo_state == ND_STATE_RECORDING )
1286 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);
1290 void wall_frame_process()
1294 for (i=0;i<Num_open_doors;i++) {
1298 d = &ActiveDoors[i];
1299 w = &Walls[d->front_wallnum[0]];
1301 if (w->state == WALL_DOOR_OPENING)
1303 else if (w->state == WALL_DOOR_CLOSING)
1305 else if (w->state == WALL_DOOR_WAITING) {
1306 d->time += FrameTime;
1308 //set flags to fix occatsional netgame problem where door is
1309 //waiting to close but open flag isn't set
1310 Assert(d->n_parts == 1);
1311 w->flags |= WALL_DOOR_OPENED;
1312 if (d->back_wallnum[0] > -1)
1313 Walls[d->back_wallnum[0]].flags |= WALL_DOOR_OPENED;
1315 if (d->time > DOOR_WAIT_TIME && is_door_free(&Segments[w->segnum],w->sidenum)) {
1316 w->state = WALL_DOOR_CLOSING;
1320 else if (w->state == WALL_DOOR_CLOSED || w->state == WALL_DOOR_OPEN) {
1321 //this shouldn't happen. if the wall is in one of these states,
1322 //there shouldn't be an activedoor entry for it. So we'll kill
1323 //the activedoor entry. Tres simple.
1325 Int3(); //a bad thing has happened, but I'll try to fix it up
1326 for (t=i;t<Num_open_doors;t++)
1327 ActiveDoors[t] = ActiveDoors[t+1];
1332 for (i=0;i<Num_cloaking_walls;i++) {
1336 d = &CloakingWalls[i];
1337 w = &Walls[d->front_wallnum];
1339 if (w->state == WALL_DOOR_CLOAKING)
1340 do_cloaking_wall_frame(i);
1341 else if (w->state == WALL_DOOR_DECLOAKING)
1342 do_decloaking_wall_frame(i);
1345 Int3(); //unexpected wall state
1350 int Num_stuck_objects=0;
1352 stuckobj Stuck_objects[MAX_STUCK_OBJECTS];
1354 // An object got stuck in a door (like a flare).
1355 // Add global entry.
1356 void add_stuck_object(object *objp, int segnum, int sidenum)
1361 wallnum = Segments[segnum].sides[sidenum].wall_num;
1363 if (wallnum != -1) {
1364 if (Walls[wallnum].flags & WALL_BLASTED)
1365 objp->flags |= OF_SHOULD_BE_DEAD;
1367 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1368 if (Stuck_objects[i].wallnum == -1) {
1369 Stuck_objects[i].wallnum = wallnum;
1370 Stuck_objects[i].objnum = OBJECT_NUMBER(objp);
1371 Stuck_objects[i].signature = objp->signature;
1372 // mprintf((0, "Added wall %i at index %i\n", wallnum, i));
1373 Num_stuck_objects++;
1377 if (i == MAX_STUCK_OBJECTS)
1378 mprintf((1, "Warning: Unable to add object %i which got stuck in wall %i to Stuck_objects\n", OBJECT_NUMBER(objp), wallnum));
1385 // --------------------------------------------------------------------------------------------------
1386 // Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here.
1387 // Removes up to one/frame.
1388 void remove_obsolete_stuck_objects(void)
1392 // Safety and efficiency code. If no stuck objects, should never get inside the IF, but this is faster.
1393 if (!Num_stuck_objects)
1396 objnum = FrameCount % MAX_STUCK_OBJECTS;
1398 if (Stuck_objects[objnum].wallnum != -1)
1399 if ((Walls[Stuck_objects[objnum].wallnum].state != WALL_DOOR_CLOSED) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) {
1400 Num_stuck_objects--;
1401 Objects[Stuck_objects[objnum].objnum].lifeleft = F1_0/8;
1402 Stuck_objects[objnum].wallnum = -1;
1407 extern void flush_fcd_cache(void);
1409 // ----------------------------------------------------------------------------------------------------
1410 // Door with wall index wallnum is opening, kill all objects stuck in it.
1411 void kill_stuck_objects(int wallnum)
1415 if (wallnum < 0 || Num_stuck_objects == 0) {
1419 Num_stuck_objects=0;
1421 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1422 if (Stuck_objects[i].wallnum == wallnum) {
1423 if (Objects[Stuck_objects[i].objnum].type == OBJ_WEAPON) {
1424 Objects[Stuck_objects[i].objnum].lifeleft = F1_0/8;
1426 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));
1427 // Int3(); // What? This looks bad. Object is not a weapon and it is stuck in a wall!
1428 Stuck_objects[i].wallnum = -1;
1429 } else if (Stuck_objects[i].wallnum != -1) {
1430 Num_stuck_objects++;
1432 // Ok, this is awful, but we need to do things whenever a door opens/closes/disappears, etc.
1438 // -- unused -- // -----------------------------------------------------------------------------------
1439 // -- unused -- // Return object id of first flare found embedded in segp:sidenum.
1440 // -- unused -- // If no flare, return -1.
1441 // -- unused -- int contains_flare(segment *segp, int sidenum)
1443 // -- unused -- int i;
1445 // -- unused -- for (i=0; i<Num_stuck_objects; i++) {
1446 // -- unused -- object *objp = &Objects[Stuck_objects[i].objnum];
1448 // -- unused -- if ((objp->type == OBJ_WEAPON) && (objp->id == FLARE_ID)) {
1449 // -- unused -- if (Walls[Stuck_objects[i].wallnum].segnum == SEGMENT_NUMBER(segp))
1450 // -- unused -- if (Walls[Stuck_objects[i].wallnum].sidenum == sidenum)
1451 // -- unused -- return OBJECT_NUMBER(objp);
1455 // -- unused -- return -1;
1458 // -----------------------------------------------------------------------------------
1459 // Initialize stuck objects array. Called at start of level
1460 void init_stuck_objects(void)
1464 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1465 Stuck_objects[i].wallnum = -1;
1467 Num_stuck_objects = 0;
1470 // -----------------------------------------------------------------------------------
1471 // Clear out all stuck objects. Called for a new ship
1472 void clear_stuck_objects(void)
1476 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1477 if (Stuck_objects[i].wallnum != -1) {
1480 objnum = Stuck_objects[i].objnum;
1482 if ((Objects[objnum].type == OBJ_WEAPON) && (Objects[objnum].id == FLARE_ID))
1483 Objects[objnum].lifeleft = F1_0/8;
1485 Stuck_objects[i].wallnum = -1;
1487 Num_stuck_objects--;
1491 Assert(Num_stuck_objects == 0);
1495 // -----------------------------------------------------------------------------------
1496 #define MAX_BLAST_GLASS_DEPTH 5
1498 void bng_process_segment(object *objp, fix damage, segment *segp, int depth, sbyte *visited)
1502 if (depth > MAX_BLAST_GLASS_DEPTH)
1507 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1512 // Process only walls which have glass.
1513 if ((tm=segp->sides[sidenum].tmap_num2) != 0) {
1516 tm &= 0x3fff; //tm without flags
1518 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))) {
1519 compute_center_point_on_side(&pnt, segp, sidenum);
1520 dist = vm_vec_dist_quick(&pnt, &objp->pos);
1521 if (dist < damage/2) {
1522 dist = find_connected_distance(&pnt, SEGMENT_NUMBER(segp), &objp->pos, objp->segnum, MAX_BLAST_GLASS_DEPTH, WID_RENDPAST_FLAG);
1523 if ((dist > 0) && (dist < damage/2))
1524 check_effect_blowup(segp, sidenum, &pnt, &Objects[objp->ctype.laser_info.parent_num], 1);
1530 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1531 int segnum = segp->children[i];
1534 if (!visited[segnum]) {
1535 if (WALL_IS_DOORWAY(segp, i) & WID_FLY_FLAG) {
1536 visited[segnum] = 1;
1537 bng_process_segment(objp, damage, &Segments[segnum], depth, visited);
1544 // -----------------------------------------------------------------------------------
1545 // objp is going to detonate
1546 // blast nearby monitors, lights, maybe other things
1547 void blast_nearby_glass(object *objp, fix damage)
1550 sbyte visited[MAX_SEGMENTS];
1553 cursegp = &Segments[objp->segnum];
1554 for (i=0; i<=Highest_segment_index; i++)
1557 visited[objp->segnum] = 1;
1558 bng_process_segment(objp, damage, cursegp, 0, visited);
1563 #define MAX_CLIP_FRAMES_D1 20
1566 * reads a wclip structure from a CFILE
1568 int wclip_read_n_d1(wclip *wc, int n, CFILE *fp)
1572 for (i = 0; i < n; i++) {
1573 wc[i].play_time = cfile_read_fix(fp);
1574 wc[i].num_frames = cfile_read_short(fp);
1575 for (j = 0; j < MAX_CLIP_FRAMES_D1; j++)
1576 wc[i].frames[j] = cfile_read_short(fp);
1577 wc[i].open_sound = cfile_read_short(fp);
1578 wc[i].close_sound = cfile_read_short(fp);
1579 wc[i].flags = cfile_read_short(fp);
1580 cfread(wc[i].filename, 13, 1, fp);
1581 wc[i].pad = cfile_read_byte(fp);
1586 #ifndef FAST_FILE_IO
1588 * reads a wclip structure from a CFILE
1590 int wclip_read_n(wclip *wc, int n, CFILE *fp)
1594 for (i = 0; i < n; i++) {
1595 wc[i].play_time = cfile_read_fix(fp);
1596 wc[i].num_frames = cfile_read_short(fp);
1597 for (j = 0; j < MAX_CLIP_FRAMES; j++)
1598 wc[i].frames[j] = cfile_read_short(fp);
1599 wc[i].open_sound = cfile_read_short(fp);
1600 wc[i].close_sound = cfile_read_short(fp);
1601 wc[i].flags = cfile_read_short(fp);
1602 cfread(wc[i].filename, 13, 1, fp);
1603 wc[i].pad = cfile_read_byte(fp);
1609 * reads a v16_wall structure from a CFILE
1611 extern void v16_wall_read(v16_wall *w, CFILE *fp)
1613 w->type = cfile_read_byte(fp);
1614 w->flags = cfile_read_byte(fp);
1615 w->hps = cfile_read_fix(fp);
1616 w->trigger = cfile_read_byte(fp);
1617 w->clip_num = cfile_read_byte(fp);
1618 w->keys = cfile_read_byte(fp);
1622 * reads a v19_wall structure from a CFILE
1624 extern void v19_wall_read(v19_wall *w, CFILE *fp)
1626 w->segnum = cfile_read_int(fp);
1627 w->sidenum = cfile_read_int(fp);
1628 w->type = cfile_read_byte(fp);
1629 w->flags = cfile_read_byte(fp);
1630 w->hps = cfile_read_fix(fp);
1631 w->trigger = cfile_read_byte(fp);
1632 w->clip_num = cfile_read_byte(fp);
1633 w->keys = cfile_read_byte(fp);
1634 w->linked_wall = cfile_read_int(fp);
1638 * reads a wall structure from a CFILE
1640 extern void wall_read(wall *w, CFILE *fp)
1642 w->segnum = cfile_read_int(fp);
1643 w->sidenum = cfile_read_int(fp);
1644 w->hps = cfile_read_fix(fp);
1645 w->linked_wall = cfile_read_int(fp);
1646 w->type = cfile_read_byte(fp);
1647 w->flags = cfile_read_byte(fp);
1648 w->state = cfile_read_byte(fp);
1649 w->trigger = cfile_read_byte(fp);
1650 w->clip_num = cfile_read_byte(fp);
1651 w->keys = cfile_read_byte(fp);
1652 w->controlling_trigger = cfile_read_byte(fp);
1653 w->cloak_value = cfile_read_byte(fp);
1657 * reads a v19_door structure from a CFILE
1659 extern void v19_door_read(v19_door *d, CFILE *fp)
1661 d->n_parts = cfile_read_int(fp);
1662 d->seg[0] = cfile_read_short(fp);
1663 d->seg[1] = cfile_read_short(fp);
1664 d->side[0] = cfile_read_short(fp);
1665 d->side[1] = cfile_read_short(fp);
1666 d->type[0] = cfile_read_short(fp);
1667 d->type[1] = cfile_read_short(fp);
1668 d->open = cfile_read_fix(fp);
1672 * reads an active_door structure from a CFILE
1674 extern void active_door_read(active_door *ad, CFILE *fp)
1676 ad->n_parts = cfile_read_int(fp);
1677 ad->front_wallnum[0] = cfile_read_short(fp);
1678 ad->front_wallnum[1] = cfile_read_short(fp);
1679 ad->back_wallnum[0] = cfile_read_short(fp);
1680 ad->back_wallnum[1] = cfile_read_short(fp);
1681 ad->time = cfile_read_fix(fp);
1685 void wall_write(wall *w, short version, CFILE *fp)
1689 PHYSFS_writeSLE32(fp, w->segnum);
1690 PHYSFS_writeSLE32(fp, w->sidenum);
1695 PHYSFSX_writeFix(fp, w->hps);
1696 PHYSFS_writeSLE32(fp, w->linked_wall);
1699 PHYSFSX_writeU8(fp, w->type);
1700 PHYSFSX_writeU8(fp, w->flags);
1703 PHYSFSX_writeFix(fp, w->hps);
1705 PHYSFSX_writeU8(fp, w->state);
1707 PHYSFSX_writeU8(fp, w->trigger);
1708 PHYSFSX_writeU8(fp, w->clip_num);
1709 PHYSFSX_writeU8(fp, w->keys);
1713 PHYSFSX_writeU8(fp, w->controlling_trigger);
1714 PHYSFSX_writeU8(fp, w->cloak_value);
1716 else if (version >= 17)
1717 PHYSFS_writeSLE32(fp, w->linked_wall);