1 /* $Id: wall.c,v 1.11 2004-05-16 11:04:32 schaffner Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Destroyable wall stuff
20 * Revision 1.1 1995/05/16 15:32:08 allender
23 * Revision 2.1 1995/03/21 14:39:04 john
24 * Ifdef'd out the NETWORK code.
26 * Revision 2.0 1995/02/27 11:28:32 john
27 * New version 2.0, which has no anonymous unions, builds with
28 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
30 * Revision 1.112 1995/02/22 13:53:07 allender
31 * remove anonymous unions from object structure
33 * Revision 1.111 1995/02/01 17:32:17 adam
34 * Took out a bogus int3.
36 * Revision 1.110 1995/02/01 17:20:24 john
39 * Revision 1.109 1995/01/21 17:39:50 matt
40 * Cleaned up laser/player hit wall confusions
42 * Revision 1.108 1995/01/21 17:14:17 rob
43 * Fixed bug in multiplayer door-butting.
45 * Revision 1.107 1995/01/18 18:57:11 rob
46 * Added new hostage door hooks.
48 * Revision 1.106 1995/01/18 18:48:18 allender
49 * removed #ifdef newdemo's. Added function call to record a door that
50 * starts to open. This fixes the rewind problem
52 * Revision 1.105 1995/01/16 11:55:39 mike
53 * make control center (and robots whose id == your playernum) not able to open doors.
55 * Revision 1.104 1994/12/11 23:07:21 matt
56 * Fixed stuck objects & blastable walls
58 * Revision 1.103 1994/12/10 16:44:34 matt
59 * Added debugging code to track down door that turns into rock
61 * Revision 1.102 1994/12/06 16:27:05 matt
64 * Revision 1.101 1994/12/02 10:50:27 yuan
67 * Revision 1.100 1994/11/30 19:41:22 rob
68 * Put in a fix so that door opening sounds travel through the door.
70 * Revision 1.99 1994/11/28 11:59:50 yuan
71 * *** empty log message ***
73 * Revision 1.98 1994/11/28 11:25:45 matt
74 * Cleaned up key hud messages
76 * Revision 1.97 1994/11/27 23:15:11 matt
77 * Made changes for new mprintf calling convention
79 * Revision 1.96 1994/11/19 15:18:29 mike
80 * rip out unused code and data.
82 * Revision 1.95 1994/11/17 14:57:12 mike
83 * moved segment validation functions from editor to main.
85 * Revision 1.94 1994/11/07 08:47:30 john
86 * Made wall state record.
88 * Revision 1.93 1994/11/04 16:06:37 rob
89 * Fixed network damage of blastable walls.
91 * Revision 1.92 1994/11/02 21:54:01 matt
92 * Don't let objects with zero size keep door from shutting
94 * Revision 1.91 1994/10/31 13:48:42 rob
95 * Fixed bug in opening doors over network/modem. Added a new message
96 * type to multi.c that communicates door openings across the net.
97 * Changed includes in multi.c and wall.c to accomplish this.
99 * Revision 1.90 1994/10/28 14:42:41 john
100 * Added sound volumes to all sound calls.
102 * Revision 1.89 1994/10/23 19:16:55 matt
103 * Fixed bug with "no key" messages
112 static char rcsid[] = "$Id: wall.c,v 1.11 2004-05-16 11:04:32 schaffner Exp $";
135 #include "fireball.h"
136 #include "textures.h"
141 #include "laser.h" // For seeing if a flare is stuck in a wall.
146 #include "editor/editor.h"
149 // Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK.
150 #define BOSS_LOCKED_DOOR_LEVEL 7
151 #define BOSS_LOCKED_DOOR_SEG 595
152 #define BOSS_LOCKED_DOOR_SIDE 5
154 wall Walls[MAX_WALLS]; // Master walls array
155 int Num_walls=0; // Number of walls
157 wclip WallAnims[MAX_WALL_ANIMS]; // Wall animations
159 //--unused-- int walls_bm_num[MAX_WALL_ANIMS];
161 //door Doors[MAX_DOORS]; // Master doors array
163 active_door ActiveDoors[MAX_DOORS];
164 int Num_open_doors; // Number of open doors
166 #define CLOAKING_WALL_TIME f1_0
168 #define MAX_CLOAKING_WALLS 10
169 cloaking_wall CloakingWalls[MAX_CLOAKING_WALLS];
170 int Num_cloaking_walls;
172 //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS];
174 //#define BM_FLAG_TRANSPARENT 1
175 //#define BM_FLAG_SUPER_TRANSPARENT 2
178 char Wall_names[7][10] = {
189 // Function prototypes
190 void kill_stuck_objects(int wallnum);
194 // This function determines whether the current segment/side is transparent
197 int check_transparency( segment * seg, int side )
199 if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) {
200 if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT )
206 if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT )
212 //define these here so I don't have to change wall_is_doorway and run
213 //the risk of screwing it up.
214 #define WID_WALL 2 // 0/1/0 wall
215 #define WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
216 #define WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
217 #define WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
218 #define WID_NO_WALL 5 // 1/0/1 no wall, can fly through
219 #define WID_EXTERNAL 8 // 0/0/0/1 don't see it, dont fly through it
221 //-----------------------------------------------------------------
222 // This function checks whether we can fly through the given side.
223 // In other words, whether or not we have a 'doorway'
227 // WID_RENDPAST_FLAG 4
229 // WID_WALL 2 // 0/1/0 wall
230 // WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall
231 // WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall
232 // WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall
233 // WID_NO_WALL 5 // 1/0/1 no wall, can fly through
234 int wall_is_doorway ( segment * seg, int side )
238 //--Covered by macro // No child.
239 //--Covered by macro if (seg->children[side] == -1)
240 //--Covered by macro return WID_WALL;
242 //--Covered by macro if (seg->children[side] == -2)
243 //--Covered by macro return WID_EXTERNAL_FLAG;
245 //--Covered by macro // No wall present.
246 //--Covered by macro if (seg->sides[side].wall_num == -1)
247 //--Covered by macro return WID_NO_WALL;
249 Assert(seg-Segments>=0 && seg-Segments<=Highest_segment_index);
250 Assert(side>=0 && side<6);
252 type = Walls[seg->sides[side].wall_num].type;
253 flags = Walls[seg->sides[side].wall_num].flags;
255 if (type == WALL_OPEN)
258 if (type == WALL_ILLUSION) {
259 if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF)
262 if (check_transparency( seg, side))
263 return WID_TRANSILLUSORY_WALL;
265 return WID_ILLUSORY_WALL;
269 if (type == WALL_BLASTABLE) {
270 if (flags & WALL_BLASTED)
271 return WID_TRANSILLUSORY_WALL;
273 if (check_transparency( seg, side))
274 return WID_TRANSPARENT_WALL;
279 if (flags & WALL_DOOR_OPENED)
280 return WID_TRANSILLUSORY_WALL;
282 if (type == WALL_CLOAKED)
283 return WID_RENDER_FLAG | WID_RENDPAST_FLAG | WID_CLOAKED_FLAG;
285 state = Walls[seg->sides[side].wall_num].state;
286 if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING))
287 return WID_TRANSPARENT_WALL;
289 // If none of the above flags are set, there is no doorway.
290 if (check_transparency( seg, side))
291 return WID_TRANSPARENT_WALL;
293 return WID_WALL; // There are children behind the door.
297 //-----------------------------------------------------------------
298 // Initializes all the walls (in other words, no special walls)
304 for (i=0;i<MAX_WALLS;i++) {
305 Walls[i].segnum = Walls[i].sidenum = -1;
306 Walls[i].type = WALL_NORMAL;
309 Walls[i].trigger = -1;
310 Walls[i].clip_num = -1;
311 Walls[i].linked_wall = -1;
314 Num_cloaking_walls = 0;
318 //-----------------------------------------------------------------
319 // Initializes one wall.
320 void wall_reset(segment *seg, int side)
324 i = seg->sides[side].wall_num;
327 mprintf((0, "Resetting Illegal Wall\n"));
331 Walls[i].segnum = seg-Segments;
332 Walls[i].sidenum = side;
333 Walls[i].type = WALL_NORMAL;
336 Walls[i].trigger = -1;
337 Walls[i].clip_num = -1;
338 Walls[i].linked_wall = -1;
342 //set the tmap_num or tmap_num2 field for a wall/door
343 void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num)
345 wclip *anim = &WallAnims[anim_num];
346 int tmap = anim->frames[frame_num];
348 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
350 if (anim->flags & WCF_TMAP1) {
351 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap;
352 if ( Newdemo_state == ND_STATE_RECORDING )
353 newdemo_record_wall_set_tmap_num1(seg-Segments,side,csegp-Segments,cside,tmap);
355 Assert(tmap!=0 && seg->sides[side].tmap_num2!=0);
356 seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap;
357 if ( Newdemo_state == ND_STATE_RECORDING )
358 newdemo_record_wall_set_tmap_num2(seg-Segments,side,csegp-Segments,cside,tmap);
363 // -------------------------------------------------------------------------------
364 //when the wall has used all its hitpoints, this will destroy it
365 void blast_blastable_wall(segment *seg, int side)
371 Assert(seg->sides[side].wall_num != -1);
373 Walls[seg->sides[side].wall_num].hps = -1; //say it's blasted
375 csegp = &Segments[seg->children[side]];
376 Connectside = find_connect_side(seg, csegp);
377 Assert(Connectside != -1);
378 cwall_num = csegp->sides[Connectside].wall_num;
379 kill_stuck_objects(seg->sides[side].wall_num);
381 kill_stuck_objects(cwall_num);
383 //if this is an exploding wall, explode it
384 if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES)
385 explode_wall(seg-Segments,side);
387 //if not exploding, set final frame, and make door passable
388 a = Walls[seg->sides[side].wall_num].clip_num;
389 n = WallAnims[a].num_frames;
390 wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1);
391 Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED;
393 Walls[cwall_num].flags |= WALL_BLASTED;
399 //-----------------------------------------------------------------
400 // Destroys a blastable wall.
401 void wall_destroy(segment *seg, int side)
403 Assert(seg->sides[side].wall_num != -1);
404 Assert(seg-Segments != 0);
406 if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
407 blast_blastable_wall( seg, side );
409 Error("Hey bub, you are trying to destroy an indestructable wall.");
412 //-----------------------------------------------------------------
413 // Deteriorate appearance of wall. (Changes bitmap (paste-ons))
414 void wall_damage(segment *seg, int side, fix damage)
416 int a, i, n, cwall_num;
418 if (seg->sides[side].wall_num == -1) {
419 mprintf((0, "Damaging illegal wall\n"));
423 if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE)
426 if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED) && Walls[seg->sides[side].wall_num].hps >= 0)
431 csegp = &Segments[seg->children[side]];
432 Connectside = find_connect_side(seg, csegp);
433 Assert(Connectside != -1);
434 cwall_num = csegp->sides[Connectside].wall_num;
435 Walls[seg->sides[side].wall_num].hps -= damage;
437 Walls[cwall_num].hps -= damage;
439 a = Walls[seg->sides[side].wall_num].clip_num;
440 n = WallAnims[a].num_frames;
442 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) {
443 blast_blastable_wall( seg, side );
445 if (Game_mode & GM_MULTI)
446 multi_send_door_open(seg-Segments, side,Walls[seg->sides[side].wall_num].flags);
451 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*(n-i)/n) {
452 wall_set_tmap_num(seg,side,csegp,Connectside,a,i);
458 //-----------------------------------------------------------------
460 void wall_open_door(segment *seg, int side)
464 int Connectside, wall_num, cwall_num;
467 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
469 w = &Walls[seg->sides[side].wall_num];
470 wall_num = w - Walls;
471 //kill_stuck_objects(seg->sides[side].wall_num);
473 if ((w->state == WALL_DOOR_OPENING) || //already opening
474 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
475 (w->state == WALL_DOOR_OPEN)) //open, & staying open
478 if (w->state == WALL_DOOR_CLOSING) { //closing, so reuse door
484 for (i=0;i<Num_open_doors;i++) { //find door
488 if (d->front_wallnum[0]==w-Walls || d->back_wallnum[0]==wall_num ||
489 (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num)))
493 if (i>=Num_open_doors && (Game_mode & GM_MULTI))
496 Assert(i<Num_open_doors); //didn't find door!
497 Assert( d!=NULL ); // Get John!
499 d->time = WallAnims[w->clip_num].play_time - d->time;
505 else { //create new door
506 Assert(w->state == WALL_DOOR_CLOSED);
508 d = &ActiveDoors[Num_open_doors];
511 Assert( Num_open_doors < MAX_DOORS );
515 w->state = WALL_DOOR_OPENING;
517 // So that door can't be shot while opening
518 csegp = &Segments[seg->children[side]];
519 Connectside = find_connect_side(seg, csegp);
520 Assert(Connectside != -1);
521 cwall_num = csegp->sides[Connectside].wall_num;
523 Walls[cwall_num].state = WALL_DOOR_OPENING;
525 //kill_stuck_objects(csegp->sides[Connectside].wall_num);
527 d->front_wallnum[0] = seg->sides[side].wall_num;
528 d->back_wallnum[0] = cwall_num;
530 Assert( seg-Segments != -1);
532 if (Newdemo_state == ND_STATE_RECORDING) {
533 newdemo_record_door_opening(seg-Segments, side);
536 if (w->linked_wall != -1) {
540 w2 = &Walls[w->linked_wall];
541 seg2 = &Segments[w2->segnum];
543 Assert(w2->linked_wall == seg->sides[side].wall_num);
544 //Assert(!(w2->flags & WALL_DOOR_OPENING || w2->flags & WALL_DOOR_OPENED));
546 w2->state = WALL_DOOR_OPENING;
548 csegp = &Segments[seg2->children[w2->sidenum]];
549 Connectside = find_connect_side(seg2, csegp);
550 Assert(Connectside != -1);
552 Walls[cwall_num].state = WALL_DOOR_OPENING;
555 d->front_wallnum[1] = w->linked_wall;
556 d->back_wallnum[1] = cwall_num;
562 if ( Newdemo_state != ND_STATE_PLAYBACK )
564 // NOTE THE LINK TO ABOVE!!!!
566 compute_center_point_on_side(&cp, seg, side );
567 if (WallAnims[w->clip_num].open_sound > -1 )
568 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
573 //-----------------------------------------------------------------
574 // start the transition from closed -> open wall
575 void start_wall_cloak(segment *seg, int side)
583 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
585 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
587 w = &Walls[seg->sides[side].wall_num];
589 if (w->type == WALL_OPEN || w->state == WALL_DOOR_CLOAKING) //already open or cloaking
592 csegp = &Segments[seg->children[side]];
593 Connectside = find_connect_side(seg, csegp);
594 Assert(Connectside != -1);
595 cwall_num = csegp->sides[Connectside].wall_num;
597 if (w->state == WALL_DOOR_DECLOAKING) { //decloaking, so reuse door
603 for (i=0;i<Num_cloaking_walls;i++) { //find door
605 d = &CloakingWalls[i];
607 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
611 Assert(i<Num_cloaking_walls); //didn't find door!
612 Assert( d!=NULL ); // Get John!
614 d->time = CLOAKING_WALL_TIME - d->time;
617 else if (w->state == WALL_DOOR_CLOSED) { //create new door
618 d = &CloakingWalls[Num_cloaking_walls];
620 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
621 Int3(); //ran out of cloaking wall slots
624 Walls[cwall_num].type = WALL_OPEN;
627 Num_cloaking_walls++;
630 Int3(); //unexpected wall state
634 w->state = WALL_DOOR_CLOAKING;
636 Walls[cwall_num].state = WALL_DOOR_CLOAKING;
638 d->front_wallnum = seg->sides[side].wall_num;
639 d->back_wallnum = cwall_num;
641 Assert( seg-Segments != -1);
643 Assert(w->linked_wall == -1);
645 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
647 compute_center_point_on_side(&cp, seg, side );
648 digi_link_sound_to_pos( SOUND_WALL_CLOAK_ON, seg-Segments, side, &cp, 0, F1_0 );
652 d->front_ls[i] = seg->sides[side].uvls[i].l;
654 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
658 //-----------------------------------------------------------------
659 // start the transition from open -> closed wall
660 void start_wall_decloak(segment *seg, int side)
668 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
670 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
672 w = &Walls[seg->sides[side].wall_num];
674 if (w->type == WALL_CLOSED || w->state == WALL_DOOR_DECLOAKING) //already closed or decloaking
677 if (w->state == WALL_DOOR_CLOAKING) { //cloaking, so reuse door
683 for (i=0;i<Num_cloaking_walls;i++) { //find door
685 d = &CloakingWalls[i];
687 if (d->front_wallnum==w-Walls || d->back_wallnum==w-Walls )
691 Assert(i<Num_cloaking_walls); //didn't find door!
692 Assert( d!=NULL ); // Get John!
694 d->time = CLOAKING_WALL_TIME - d->time;
697 else if (w->state == WALL_DOOR_CLOSED) { //create new door
698 d = &CloakingWalls[Num_cloaking_walls];
700 if (Num_cloaking_walls >= MAX_CLOAKING_WALLS) { //no more!
701 Int3(); //ran out of cloaking wall slots
702 /* what is this _doing_ here?
703 w->type = WALL_CLOSED;
704 Walls[csegp->sides[Connectside].wall_num].type = WALL_CLOSED;
708 Num_cloaking_walls++;
711 Int3(); //unexpected wall state
715 w->state = WALL_DOOR_DECLOAKING;
717 // So that door can't be shot while opening
718 csegp = &Segments[seg->children[side]];
719 Connectside = find_connect_side(seg, csegp);
720 Assert(Connectside != -1);
721 cwall_num = csegp->sides[Connectside].wall_num;
723 Walls[cwall_num].state = WALL_DOOR_DECLOAKING;
725 d->front_wallnum = seg->sides[side].wall_num;
726 d->back_wallnum = csegp->sides[Connectside].wall_num;
728 Assert( seg-Segments != -1);
730 Assert(w->linked_wall == -1);
732 if ( Newdemo_state != ND_STATE_PLAYBACK ) {
734 compute_center_point_on_side(&cp, seg, side );
735 digi_link_sound_to_pos( SOUND_WALL_CLOAK_OFF, seg-Segments, side, &cp, 0, F1_0 );
739 d->front_ls[i] = seg->sides[side].uvls[i].l;
741 d->back_ls[i] = csegp->sides[Connectside].uvls[i].l;
745 //-----------------------------------------------------------------
746 // This function closes the specified door and restores the closed
747 // door texture. This is called when the animation is done
748 void wall_close_door_num(int door_num)
754 d = &ActiveDoors[door_num];
756 for (p=0;p<d->n_parts;p++) {
758 int Connectside, side;
759 segment *csegp, *seg;
761 w = &Walls[d->front_wallnum[p]];
763 seg = &Segments[w->segnum];
766 Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall
768 csegp = &Segments[seg->children[side]];
769 Connectside = find_connect_side(seg, csegp);
770 Assert(Connectside != -1);
771 cwall_num = csegp->sides[Connectside].wall_num;
772 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED;
774 Walls[cwall_num].state = WALL_DOOR_CLOSED;
776 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0);
780 for (i=door_num;i<Num_open_doors;i++)
781 ActiveDoors[i] = ActiveDoors[i+1];
787 int check_poke(int objnum,int segnum,int side)
789 object *obj = &Objects[objnum];
791 //note: don't let objects with zero size block door
793 if (obj->size && get_seg_masks(&obj->pos,segnum,obj->size).sidemask & (1<<side))
794 return 1; //pokes through side!
796 return 0; //does not!
800 //returns true of door in unobjstructed (& thus can close)
801 int is_door_free(segment *seg,int side)
807 csegp = &Segments[seg->children[side]];
808 Connectside = find_connect_side(seg, csegp);
809 Assert(Connectside != -1);
811 //go through each object in each of two segments, and see if
812 //it pokes into the connecting seg
814 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
815 if (Objects[objnum].type!=OBJ_WEAPON && Objects[objnum].type!=OBJ_FIREBALL && check_poke(objnum,seg-Segments,side))
818 for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next)
819 if (Objects[objnum].type!=OBJ_WEAPON && Objects[objnum].type!=OBJ_FIREBALL && check_poke(objnum,csegp-Segments,Connectside))
822 return 1; //doorway is free!
827 //-----------------------------------------------------------------
829 void wall_close_door(segment *seg, int side)
833 int Connectside, wall_num, cwall_num;
836 Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall
838 w = &Walls[seg->sides[side].wall_num];
839 wall_num = w - Walls;
840 if ((w->state == WALL_DOOR_CLOSING) || //already closing
841 (w->state == WALL_DOOR_WAITING) || //open, waiting to close
842 (w->state == WALL_DOOR_CLOSED)) //closed
845 if (!is_door_free(seg,side))
848 if (w->state == WALL_DOOR_OPENING) { //reuse door
854 for (i=0;i<Num_open_doors;i++) { //find door
858 if (d->front_wallnum[0]==wall_num || d->back_wallnum[0]==wall_num ||
859 (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num)))
863 Assert(i<Num_open_doors); //didn't find door!
864 Assert( d!=NULL ); // Get John!
866 d->time = WallAnims[w->clip_num].play_time - d->time;
872 else { //create new door
873 Assert(w->state == WALL_DOOR_OPEN);
874 d = &ActiveDoors[Num_open_doors];
877 Assert( Num_open_doors < MAX_DOORS );
880 w->state = WALL_DOOR_CLOSING;
882 // So that door can't be shot while opening
883 csegp = &Segments[seg->children[side]];
884 Connectside = find_connect_side(seg, csegp);
885 Assert(Connectside != -1);
886 cwall_num = csegp->sides[Connectside].wall_num;
888 Walls[cwall_num].state = WALL_DOOR_CLOSING;
890 d->front_wallnum[0] = seg->sides[side].wall_num;
891 d->back_wallnum[0] = cwall_num;
893 Assert( seg-Segments != -1);
895 if (Newdemo_state == ND_STATE_RECORDING) {
896 newdemo_record_door_opening(seg-Segments, side);
899 if (w->linked_wall != -1) {
900 Int3(); //don't think we ever used linked walls
906 if ( Newdemo_state != ND_STATE_PLAYBACK )
908 // NOTE THE LINK TO ABOVE!!!!
910 compute_center_point_on_side(&cp, seg, side );
911 if (WallAnims[w->clip_num].open_sound > -1 )
912 digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
917 //-----------------------------------------------------------------
918 // Animates opening of a door.
919 // Called in the game loop.
920 void do_door_open(int door_num)
925 Assert(door_num != -1); //Trying to do_door_open on illegal door
927 d = &ActiveDoors[door_num];
929 for (p=0;p<d->n_parts;p++) {
931 int Connectside, side;
932 segment *csegp, *seg;
933 fix time_elapsed, time_total, one_frame;
936 w = &Walls[d->front_wallnum[p]];
937 kill_stuck_objects(d->front_wallnum[p]);
938 kill_stuck_objects(d->back_wallnum[p]);
940 seg = &Segments[w->segnum];
943 Assert(seg->sides[side].wall_num != -1); //Trying to do_door_open on illegal wall
945 csegp = &Segments[seg->children[side]];
946 Connectside = find_connect_side(seg, csegp);
947 Assert(Connectside != -1);
949 d->time += FrameTime;
951 time_elapsed = d->time;
952 n = WallAnims[w->clip_num].num_frames;
953 time_total = WallAnims[w->clip_num].play_time;
955 one_frame = time_total/n;
957 i = time_elapsed/one_frame;
960 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
963 Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED;
964 Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED;
968 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1);
970 // If our door is not automatic just remove it from the list.
971 if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) {
972 for (i=door_num;i<Num_open_doors;i++)
973 ActiveDoors[i] = ActiveDoors[i+1];
975 Walls[seg->sides[side].wall_num].state = WALL_DOOR_OPEN;
976 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPEN;
980 Walls[seg->sides[side].wall_num].state = WALL_DOOR_WAITING;
981 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING;
983 ActiveDoors[Num_open_doors].time = 0; //counts up
991 //-----------------------------------------------------------------
992 // Animates and processes the closing of a door.
993 // Called from the game loop.
994 void do_door_close(int door_num)
1000 Assert(door_num != -1); //Trying to do_door_open on illegal door
1002 d = &ActiveDoors[door_num];
1004 w = &Walls[d->front_wallnum[0]];
1006 //check for objects in doorway before closing
1007 if (w->flags & WALL_DOOR_AUTO)
1008 if (!is_door_free(&Segments[w->segnum],w->sidenum)) {
1009 digi_kill_sound_linked_to_segment(w->segnum,w->sidenum,-1);
1010 wall_open_door(&Segments[w->segnum],w->sidenum); //re-open door
1014 for (p=0;p<d->n_parts;p++) {
1016 int Connectside, side;
1017 segment *csegp, *seg;
1018 fix time_elapsed, time_total, one_frame;
1021 w = &Walls[d->front_wallnum[p]];
1023 seg = &Segments[w->segnum];
1026 if (seg->sides[side].wall_num == -1) {
1027 mprintf((0, "Trying to do_door_close on Illegal wall\n"));
1031 //if here, must be auto door
1032 // Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO);
1033 //don't assert here, because now we have triggers to close non-auto doors
1035 // Otherwise, close it.
1036 csegp = &Segments[seg->children[side]];
1037 Connectside = find_connect_side(seg, csegp);
1038 Assert(Connectside != -1);
1041 if ( Newdemo_state != ND_STATE_PLAYBACK )
1042 // NOTE THE LINK TO ABOVE!!
1043 if (p==0) //only play one sound for linked doors
1044 if ( d->time==0 ) { //first time
1046 compute_center_point_on_side(&cp, seg, side );
1047 if (WallAnims[w->clip_num].close_sound > -1 )
1048 digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, seg-Segments, side, &cp, 0, F1_0 );
1051 d->time += FrameTime;
1053 time_elapsed = d->time;
1054 n = WallAnims[w->clip_num].num_frames;
1055 time_total = WallAnims[w->clip_num].play_time;
1057 one_frame = time_total/n;
1059 i = n-time_elapsed/one_frame-1;
1062 Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED;
1063 Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED;
1068 wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
1070 Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING;
1071 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
1073 ActiveDoors[Num_open_doors].time = 0; //counts up
1076 wall_close_door_num(door_num);
1081 //-----------------------------------------------------------------
1082 // Turns off an illusionary wall (This will be used primarily for
1083 // wall switches or triggers that can turn on/off illusionary walls.)
1084 void wall_illusion_off(segment *seg, int side)
1089 csegp = &Segments[seg->children[side]];
1090 cside = find_connect_side(seg, csegp);
1091 Assert(cside != -1);
1093 if (seg->sides[side].wall_num == -1) {
1094 mprintf((0, "Trying to shut off illusion illegal wall\n"));
1098 Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF;
1099 Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF;
1101 kill_stuck_objects(seg->sides[side].wall_num);
1102 kill_stuck_objects(csegp->sides[cside].wall_num);
1105 //-----------------------------------------------------------------
1106 // Turns on an illusionary wall (This will be used primarily for
1107 // wall switches or triggers that can turn on/off illusionary walls.)
1108 void wall_illusion_on(segment *seg, int side)
1113 csegp = &Segments[seg->children[side]];
1114 cside = find_connect_side(seg, csegp);
1115 Assert(cside != -1);
1117 if (seg->sides[side].wall_num == -1) {
1118 mprintf((0, "Trying to turn on illusion illegal wall\n"));
1122 Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF;
1123 Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF;
1126 // -----------------------------------------------------------------------------
1127 // Allowed to open the normally locked special boss door if in multiplayer mode.
1128 int special_boss_opening_allowed(int segnum, int sidenum)
1130 if (Game_mode & GM_MULTI)
1131 return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE);
1136 //-----------------------------------------------------------------
1137 // Determines what happens when a wall is shot
1138 //returns info about wall. see wall.h for codes
1139 //obj is the object that hit...either a weapon or the player himself
1140 //playernum is the number the player who hit the wall or fired the weapon,
1141 //or -1 if a robot fired the weapon
1142 int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj )
1147 Assert (seg-Segments != -1);
1149 // If it is not a "wall" then just return.
1150 if ( seg->sides[side].wall_num < 0 )
1151 return WHP_NOT_SPECIAL;
1153 w = &Walls[seg->sides[side].wall_num];
1155 if ( Newdemo_state == ND_STATE_RECORDING )
1156 newdemo_record_wall_hit_process( seg-Segments, side, damage, playernum );
1158 if (w->type == WALL_BLASTABLE) {
1159 if (obj->ctype.laser_info.parent_type == OBJ_PLAYER)
1160 wall_damage(seg, side, damage);
1161 return WHP_BLASTABLE;
1164 if (playernum != Player_num) //return if was robot fire
1165 return WHP_NOT_SPECIAL;
1167 Assert( playernum > -1 );
1169 // Determine whether player is moving forward. If not, don't say negative
1170 // messages because he probably didn't intentionally hit the door.
1171 if (obj->type == OBJ_PLAYER)
1172 show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0);
1173 else if (obj->type == OBJ_ROBOT)
1175 else if ((obj->type == OBJ_WEAPON) && (obj->ctype.laser_info.parent_type == OBJ_ROBOT))
1180 if (w->keys == KEY_BLUE)
1181 if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) {
1182 if ( playernum==Player_num )
1184 HUD_init_message("%s %s",TXT_BLUE,TXT_ACCESS_DENIED);
1188 if (w->keys == KEY_RED)
1189 if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) {
1190 if ( playernum==Player_num )
1192 HUD_init_message("%s %s",TXT_RED,TXT_ACCESS_DENIED);
1196 if (w->keys == KEY_GOLD)
1197 if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) {
1198 if ( playernum==Player_num )
1200 HUD_init_message("%s %s",TXT_YELLOW,TXT_ACCESS_DENIED);
1204 if (w->type == WALL_DOOR)
1206 if ((w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(seg-Segments, side)) ) {
1207 if ( playernum==Player_num )
1209 HUD_init_message(TXT_CANT_OPEN_DOOR);
1213 if (w->state != WALL_DOOR_OPENING)
1215 wall_open_door(seg, side);
1217 if (Game_mode & GM_MULTI)
1218 multi_send_door_open(seg-Segments, side,w->flags);
1226 return WHP_NOT_SPECIAL; //default is treat like normal wall
1229 //-----------------------------------------------------------------
1230 // Opens doors/destroys wall/shuts off triggers.
1231 void wall_toggle(segment *seg, int side)
1235 if (seg - Segments > Highest_segment_index)
1237 Warning("Can't toggle side %d of segment %d - nonexistent segment!\n", side, seg-Segments);
1240 Assert( side < MAX_SIDES_PER_SEGMENT );
1242 wall_num = seg->sides[side].wall_num;
1244 if (wall_num == -1) {
1245 mprintf((0, "Illegal wall_toggle\n"));
1249 if ( Newdemo_state == ND_STATE_RECORDING )
1250 newdemo_record_wall_toggle(seg-Segments, side );
1252 if (Walls[wall_num].type == WALL_BLASTABLE)
1253 wall_destroy(seg, side);
1255 if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED))
1256 wall_open_door(seg, side);
1261 //-----------------------------------------------------------------
1262 // Tidy up Walls array for load/save purposes.
1267 if (Num_walls < 0) {
1268 mprintf((0, "Illegal Num_walls\n"));
1272 for (i=Num_walls;i<MAX_WALLS;i++) {
1273 Walls[i].type = WALL_NORMAL;
1276 Walls[i].trigger = -1;
1277 Walls[i].clip_num = -1;
1281 void do_cloaking_wall_frame(int cloaking_wall_num)
1284 wall *wfront,*wback;
1286 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1288 d = &CloakingWalls[cloaking_wall_num];
1289 wfront = &Walls[d->front_wallnum];
1290 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1292 d->time += FrameTime;
1294 if (d->time > CLOAKING_WALL_TIME) {
1297 wfront->type = WALL_OPEN;
1298 wfront->state = WALL_DOOR_CLOSED; //why closed? why not?
1300 wback->type = WALL_OPEN;
1301 wback->state = WALL_DOOR_CLOSED; //why closed? why not?
1304 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1305 CloakingWalls[i] = CloakingWalls[i+1];
1306 Num_cloaking_walls--;
1309 else if (d->time > CLOAKING_WALL_TIME/2) {
1310 int old_type=wfront->type;
1312 wfront->cloak_value = ((d->time - CLOAKING_WALL_TIME/2) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1314 wback->cloak_value = wfront->cloak_value;
1316 if (old_type != WALL_CLOAKED) { //just switched
1319 wfront->type = WALL_CLOAKED;
1321 wback->type = WALL_CLOAKED;
1324 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1326 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1334 light_scale = fixdiv(CLOAKING_WALL_TIME/2-d->time,CLOAKING_WALL_TIME/2);
1337 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1339 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1343 if ( Newdemo_state == ND_STATE_RECORDING )
1344 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);
1348 void do_decloaking_wall_frame(int cloaking_wall_num)
1351 wall *wfront,*wback;
1353 if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
1355 d = &CloakingWalls[cloaking_wall_num];
1356 wfront = &Walls[d->front_wallnum];
1357 wback = (d->back_wallnum > -1) ? Walls + d->back_wallnum : NULL;
1359 d->time += FrameTime;
1361 if (d->time > CLOAKING_WALL_TIME) {
1364 wfront->state = WALL_DOOR_CLOSED;
1366 wback->state = WALL_DOOR_CLOSED;
1369 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = d->front_ls[i];
1371 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = d->back_ls[i];
1374 for (i=cloaking_wall_num;i<Num_cloaking_walls;i++)
1375 CloakingWalls[i] = CloakingWalls[i+1];
1376 Num_cloaking_walls--;
1379 else if (d->time > CLOAKING_WALL_TIME/2) { //fading in
1383 wfront->type = wback->type = WALL_CLOSED;
1385 light_scale = fixdiv(d->time-CLOAKING_WALL_TIME/2,CLOAKING_WALL_TIME/2);
1388 Segments[wfront->segnum].sides[wfront->sidenum].uvls[i].l = fixmul(d->front_ls[i],light_scale);
1390 Segments[wback->segnum].sides[wback->sidenum].uvls[i].l = fixmul(d->back_ls[i],light_scale);
1393 else { //cloaking in
1394 wfront->cloak_value = ((CLOAKING_WALL_TIME/2 - d->time) * (GR_FADE_LEVELS-2)) / (CLOAKING_WALL_TIME/2);
1395 wfront->type = WALL_CLOAKED;
1397 wback->cloak_value = wfront->cloak_value;
1398 wback->type = WALL_CLOAKED;
1402 if ( Newdemo_state == ND_STATE_RECORDING )
1403 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);
1407 void wall_frame_process()
1411 for (i=0;i<Num_open_doors;i++) {
1415 d = &ActiveDoors[i];
1416 w = &Walls[d->front_wallnum[0]];
1418 if (w->state == WALL_DOOR_OPENING)
1420 else if (w->state == WALL_DOOR_CLOSING)
1422 else if (w->state == WALL_DOOR_WAITING) {
1423 d->time += FrameTime;
1425 //set flags to fix occatsional netgame problem where door is
1426 //waiting to close but open flag isn't set
1427 Assert(d->n_parts == 1);
1428 w->flags |= WALL_DOOR_OPENED;
1429 if (d->back_wallnum[0] > -1)
1430 Walls[d->back_wallnum[0]].flags |= WALL_DOOR_OPENED;
1432 if (d->time > DOOR_WAIT_TIME && is_door_free(&Segments[w->segnum],w->sidenum)) {
1433 w->state = WALL_DOOR_CLOSING;
1437 else if (w->state == WALL_DOOR_CLOSED || w->state == WALL_DOOR_OPEN) {
1438 //this shouldn't happen. if the wall is in one of these states,
1439 //there shouldn't be an activedoor entry for it. So we'll kill
1440 //the activedoor entry. Tres simple.
1442 Int3(); //a bad thing has happened, but I'll try to fix it up
1443 for (t=i;t<Num_open_doors;t++)
1444 ActiveDoors[t] = ActiveDoors[t+1];
1449 for (i=0;i<Num_cloaking_walls;i++) {
1453 d = &CloakingWalls[i];
1454 w = &Walls[d->front_wallnum];
1456 if (w->state == WALL_DOOR_CLOAKING)
1457 do_cloaking_wall_frame(i);
1458 else if (w->state == WALL_DOOR_DECLOAKING)
1459 do_decloaking_wall_frame(i);
1462 Int3(); //unexpected wall state
1467 int Num_stuck_objects=0;
1469 stuckobj Stuck_objects[MAX_STUCK_OBJECTS];
1471 // An object got stuck in a door (like a flare).
1472 // Add global entry.
1473 void add_stuck_object(object *objp, int segnum, int sidenum)
1478 wallnum = Segments[segnum].sides[sidenum].wall_num;
1480 if (wallnum != -1) {
1481 if (Walls[wallnum].flags & WALL_BLASTED)
1482 objp->flags |= OF_SHOULD_BE_DEAD;
1484 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1485 if (Stuck_objects[i].wallnum == -1) {
1486 Stuck_objects[i].wallnum = wallnum;
1487 Stuck_objects[i].objnum = objp-Objects;
1488 Stuck_objects[i].signature = objp->signature;
1489 // mprintf((0, "Added wall %i at index %i\n", wallnum, i));
1490 Num_stuck_objects++;
1494 if (i == MAX_STUCK_OBJECTS)
1495 mprintf((1, "Warning: Unable to add object %i which got stuck in wall %i to Stuck_objects\n", objp-Objects, wallnum));
1502 // --------------------------------------------------------------------------------------------------
1503 // Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here.
1504 // Removes up to one/frame.
1505 void remove_obsolete_stuck_objects(void)
1509 // Safety and efficiency code. If no stuck objects, should never get inside the IF, but this is faster.
1510 if (!Num_stuck_objects)
1513 objnum = FrameCount % MAX_STUCK_OBJECTS;
1515 if (Stuck_objects[objnum].wallnum != -1)
1516 if ((Walls[Stuck_objects[objnum].wallnum].state != WALL_DOOR_CLOSED) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) {
1517 Num_stuck_objects--;
1518 Objects[Stuck_objects[objnum].objnum].lifeleft = F1_0/8;
1519 Stuck_objects[objnum].wallnum = -1;
1524 extern void flush_fcd_cache(void);
1526 // ----------------------------------------------------------------------------------------------------
1527 // Door with wall index wallnum is opening, kill all objects stuck in it.
1528 void kill_stuck_objects(int wallnum)
1532 if (wallnum < 0 || Num_stuck_objects == 0) {
1536 Num_stuck_objects=0;
1538 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1539 if (Stuck_objects[i].wallnum == wallnum) {
1540 if (Objects[Stuck_objects[i].objnum].type == OBJ_WEAPON) {
1541 Objects[Stuck_objects[i].objnum].lifeleft = F1_0/8;
1543 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));
1544 // Int3(); // What? This looks bad. Object is not a weapon and it is stuck in a wall!
1545 Stuck_objects[i].wallnum = -1;
1546 } else if (Stuck_objects[i].wallnum != -1) {
1547 Num_stuck_objects++;
1549 // Ok, this is awful, but we need to do things whenever a door opens/closes/disappears, etc.
1555 // -- unused -- // -----------------------------------------------------------------------------------
1556 // -- unused -- // Return object id of first flare found embedded in segp:sidenum.
1557 // -- unused -- // If no flare, return -1.
1558 // -- unused -- int contains_flare(segment *segp, int sidenum)
1560 // -- unused -- int i;
1562 // -- unused -- for (i=0; i<Num_stuck_objects; i++) {
1563 // -- unused -- object *objp = &Objects[Stuck_objects[i].objnum];
1565 // -- unused -- if ((objp->type == OBJ_WEAPON) && (objp->id == FLARE_ID)) {
1566 // -- unused -- if (Walls[Stuck_objects[i].wallnum].segnum == segp-Segments)
1567 // -- unused -- if (Walls[Stuck_objects[i].wallnum].sidenum == sidenum)
1568 // -- unused -- return objp-Objects;
1572 // -- unused -- return -1;
1575 // -----------------------------------------------------------------------------------
1576 // Initialize stuck objects array. Called at start of level
1577 void init_stuck_objects(void)
1581 for (i=0; i<MAX_STUCK_OBJECTS; i++)
1582 Stuck_objects[i].wallnum = -1;
1584 Num_stuck_objects = 0;
1587 // -----------------------------------------------------------------------------------
1588 // Clear out all stuck objects. Called for a new ship
1589 void clear_stuck_objects(void)
1593 for (i=0; i<MAX_STUCK_OBJECTS; i++) {
1594 if (Stuck_objects[i].wallnum != -1) {
1597 objnum = Stuck_objects[i].objnum;
1599 if ((Objects[objnum].type == OBJ_WEAPON) && (Objects[objnum].id == FLARE_ID))
1600 Objects[objnum].lifeleft = F1_0/8;
1602 Stuck_objects[i].wallnum = -1;
1604 Num_stuck_objects--;
1608 Assert(Num_stuck_objects == 0);
1612 // -----------------------------------------------------------------------------------
1613 #define MAX_BLAST_GLASS_DEPTH 5
1615 void bng_process_segment(object *objp, fix damage, segment *segp, int depth, sbyte *visited)
1619 if (depth > MAX_BLAST_GLASS_DEPTH)
1624 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1629 // Process only walls which have glass.
1630 if ((tm=segp->sides[sidenum].tmap_num2) != 0) {
1633 tm &= 0x3fff; //tm without flags
1635 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))) {
1636 compute_center_point_on_side(&pnt, segp, sidenum);
1637 dist = vm_vec_dist_quick(&pnt, &objp->pos);
1638 if (dist < damage/2) {
1639 dist = find_connected_distance(&pnt, segp-Segments, &objp->pos, objp->segnum, MAX_BLAST_GLASS_DEPTH, WID_RENDPAST_FLAG);
1640 if ((dist > 0) && (dist < damage/2))
1641 check_effect_blowup(segp, sidenum, &pnt, &Objects[objp->ctype.laser_info.parent_num], 1);
1647 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1648 int segnum = segp->children[i];
1651 if (!visited[segnum]) {
1652 if (WALL_IS_DOORWAY(segp, i) & WID_FLY_FLAG) {
1653 visited[segnum] = 1;
1654 bng_process_segment(objp, damage, &Segments[segnum], depth, visited);
1661 // -----------------------------------------------------------------------------------
1662 // objp is going to detonate
1663 // blast nearby monitors, lights, maybe other things
1664 void blast_nearby_glass(object *objp, fix damage)
1667 sbyte visited[MAX_SEGMENTS];
1670 cursegp = &Segments[objp->segnum];
1671 for (i=0; i<=Highest_segment_index; i++)
1674 visited[objp->segnum] = 1;
1675 bng_process_segment(objp, damage, cursegp, 0, visited);
1680 #define MAX_CLIP_FRAMES_D1 20
1683 * reads a wclip structure from a CFILE
1685 int wclip_read_n_d1(wclip *wc, int n, CFILE *fp)
1689 for (i = 0; i < n; i++) {
1690 wc[i].play_time = cfile_read_fix(fp);
1691 wc[i].num_frames = cfile_read_short(fp);
1692 for (j = 0; j < MAX_CLIP_FRAMES_D1; j++)
1693 wc[i].frames[j] = cfile_read_short(fp);
1694 wc[i].open_sound = cfile_read_short(fp);
1695 wc[i].close_sound = cfile_read_short(fp);
1696 wc[i].flags = cfile_read_short(fp);
1697 cfread(wc[i].filename, 13, 1, fp);
1698 wc[i].pad = cfile_read_byte(fp);
1703 #ifndef FAST_FILE_IO
1705 * reads a wclip structure from a CFILE
1707 int wclip_read_n(wclip *wc, int n, CFILE *fp)
1711 for (i = 0; i < n; i++) {
1712 wc[i].play_time = cfile_read_fix(fp);
1713 wc[i].num_frames = cfile_read_short(fp);
1714 for (j = 0; j < MAX_CLIP_FRAMES; j++)
1715 wc[i].frames[j] = cfile_read_short(fp);
1716 wc[i].open_sound = cfile_read_short(fp);
1717 wc[i].close_sound = cfile_read_short(fp);
1718 wc[i].flags = cfile_read_short(fp);
1719 cfread(wc[i].filename, 13, 1, fp);
1720 wc[i].pad = cfile_read_byte(fp);
1726 * reads a v16_wall structure from a CFILE
1728 extern void v16_wall_read(v16_wall *w, CFILE *fp)
1730 w->type = cfile_read_byte(fp);
1731 w->flags = cfile_read_byte(fp);
1732 w->hps = cfile_read_fix(fp);
1733 w->trigger = cfile_read_byte(fp);
1734 w->clip_num = cfile_read_byte(fp);
1735 w->keys = cfile_read_byte(fp);
1739 * reads a v19_wall structure from a CFILE
1741 extern void v19_wall_read(v19_wall *w, CFILE *fp)
1743 w->segnum = cfile_read_int(fp);
1744 w->sidenum = cfile_read_int(fp);
1745 w->type = cfile_read_byte(fp);
1746 w->flags = cfile_read_byte(fp);
1747 w->hps = cfile_read_fix(fp);
1748 w->trigger = cfile_read_byte(fp);
1749 w->clip_num = cfile_read_byte(fp);
1750 w->keys = cfile_read_byte(fp);
1751 w->linked_wall = cfile_read_int(fp);
1755 * reads a wall structure from a CFILE
1757 extern void wall_read(wall *w, CFILE *fp)
1759 w->segnum = cfile_read_int(fp);
1760 w->sidenum = cfile_read_int(fp);
1761 w->hps = cfile_read_fix(fp);
1762 w->linked_wall = cfile_read_int(fp);
1763 w->type = cfile_read_byte(fp);
1764 w->flags = cfile_read_byte(fp);
1765 w->state = cfile_read_byte(fp);
1766 w->trigger = cfile_read_byte(fp);
1767 w->clip_num = cfile_read_byte(fp);
1768 w->keys = cfile_read_byte(fp);
1769 w->controlling_trigger = cfile_read_byte(fp);
1770 w->cloak_value = cfile_read_byte(fp);
1774 * reads a v19_door structure from a CFILE
1776 extern void v19_door_read(v19_door *d, CFILE *fp)
1778 d->n_parts = cfile_read_int(fp);
1779 d->seg[0] = cfile_read_short(fp);
1780 d->seg[1] = cfile_read_short(fp);
1781 d->side[0] = cfile_read_short(fp);
1782 d->side[1] = cfile_read_short(fp);
1783 d->type[0] = cfile_read_short(fp);
1784 d->type[1] = cfile_read_short(fp);
1785 d->open = cfile_read_fix(fp);
1789 * reads an active_door structure from a CFILE
1791 extern void active_door_read(active_door *ad, CFILE *fp)
1793 ad->n_parts = cfile_read_int(fp);
1794 ad->front_wallnum[0] = cfile_read_short(fp);
1795 ad->front_wallnum[1] = cfile_read_short(fp);
1796 ad->back_wallnum[0] = cfile_read_short(fp);
1797 ad->back_wallnum[1] = cfile_read_short(fp);
1798 ad->time = cfile_read_fix(fp);