home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / wall.c < prev    next >
Text File  |  1998-06-08  |  30KB  |  1,051 lines

  1. /*
  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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/main/rcs/wall.c $
  15.  * $Revision: 2.1 $
  16.  * $Author: john $
  17.  * $Date: 1995/03/21 14:39:04 $
  18.  * 
  19.  * Destroyable wall stuff
  20.  * 
  21.  * $Log: wall.c $
  22.  * Revision 2.1  1995/03/21  14:39:04  john
  23.  * Ifdef'd out the NETWORK code.
  24.  * 
  25.  * Revision 2.0  1995/02/27  11:28:32  john
  26.  * New version 2.0, which has no anonymous unions, builds with
  27.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  28.  * 
  29.  * Revision 1.112  1995/02/22  13:53:07  allender
  30.  * remove anonymous unions from object structure
  31.  * 
  32.  * Revision 1.111  1995/02/01  17:32:17  adam
  33.  * Took out a bogus int3.
  34.  * 
  35.  * Revision 1.110  1995/02/01  17:20:24  john
  36.  * Lintized.
  37.  * 
  38.  * Revision 1.109  1995/01/21  17:39:50  matt
  39.  * Cleaned up laser/player hit wall confusions
  40.  * 
  41.  * Revision 1.108  1995/01/21  17:14:17  rob
  42.  * Fixed bug in multiplayer door-butting.
  43.  * 
  44.  * Revision 1.107  1995/01/18  18:57:11  rob
  45.  * Added new hostage door hooks.
  46.  * 
  47.  * Revision 1.106  1995/01/18  18:48:18  allender
  48.  * removed #ifdef newdemo's.  Added function call to record a door that
  49.  * starts to open. This fixes the rewind problem
  50.  * 
  51.  * Revision 1.105  1995/01/16  11:55:39  mike
  52.  * make control center (and robots whose id == your playernum) not able to open doors.
  53.  * 
  54.  * Revision 1.104  1994/12/11  23:07:21  matt
  55.  * Fixed stuck objects & blastable walls
  56.  * 
  57.  * Revision 1.103  1994/12/10  16:44:34  matt
  58.  * Added debugging code to track down door that turns into rock
  59.  * 
  60.  * Revision 1.102  1994/12/06  16:27:05  matt
  61.  * Added debugging
  62.  * 
  63.  * Revision 1.101  1994/12/02  10:50:27  yuan
  64.  * Localization
  65.  * 
  66.  * Revision 1.100  1994/11/30  19:41:22  rob
  67.  * Put in a fix so that door opening sounds travel through the door.
  68.  * 
  69.  * Revision 1.99  1994/11/28  11:59:50  yuan
  70.  * *** empty log message ***
  71.  * 
  72.  * Revision 1.98  1994/11/28  11:25:45  matt
  73.  * Cleaned up key hud messages
  74.  * 
  75.  * Revision 1.97  1994/11/27  23:15:11  matt
  76.  * Made changes for new mprintf calling convention
  77.  * 
  78.  * Revision 1.96  1994/11/19  15:18:29  mike
  79.  * rip out unused code and data.
  80.  * 
  81.  * Revision 1.95  1994/11/17  14:57:12  mike
  82.  * moved segment validation functions from editor to main.
  83.  * 
  84.  * Revision 1.94  1994/11/07  08:47:30  john
  85.  * Made wall state record.
  86.  * 
  87.  * Revision 1.93  1994/11/04  16:06:37  rob
  88.  * Fixed network damage of blastable walls.
  89.  * 
  90.  * Revision 1.92  1994/11/02  21:54:01  matt
  91.  * Don't let objects with zero size keep door from shutting
  92.  * 
  93.  * Revision 1.91  1994/10/31  13:48:42  rob
  94.  * Fixed bug in opening doors over network/modem.  Added a new message
  95.  * type to multi.c that communicates door openings across the net. 
  96.  * Changed includes in multi.c and wall.c to accomplish this.
  97.  * 
  98.  * Revision 1.90  1994/10/28  14:42:41  john
  99.  * Added sound volumes to all sound calls.
  100.  * 
  101.  * Revision 1.89  1994/10/23  19:16:55  matt
  102.  * Fixed bug with "no key" messages
  103.  * 
  104.  */
  105.  
  106.  
  107. #pragma off (unreferenced)
  108. static char rcsid[] = "$Id: wall.c 2.1 1995/03/21 14:39:04 john Exp $";
  109. #pragma on (unreferenced)
  110.  
  111. #include <stdio.h>
  112. #include <stdlib.h>
  113. #include <math.h>
  114. #include <string.h>
  115.  
  116. #include "mono.h"
  117. #include "gr.h"
  118. #include "wall.h"
  119. #include "switch.h"
  120. #include "inferno.h"
  121. #include "editor\editor.h"
  122. #include "segment.h"
  123. #include "error.h"
  124. #include "gameseg.h"
  125. #include "game.h"
  126. #include "bm.h"
  127. #include "vclip.h"
  128. #include "player.h"
  129. #include "gauges.h"
  130. #include "text.h"
  131. #include "fireball.h"
  132. #include "textures.h"
  133. #include "sounds.h"
  134. #include "newdemo.h"
  135. #include "multi.h"
  136. #include "gameseq.h"
  137.  
  138. //    Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK.
  139. #define    BOSS_LOCKED_DOOR_LEVEL    7
  140. #define    BOSS_LOCKED_DOOR_SEG        595
  141. #define    BOSS_LOCKED_DOOR_SIDE    5
  142.  
  143. wall Walls[MAX_WALLS];                    // Master walls array
  144. int Num_walls=0;                            // Number of walls
  145.  
  146. wclip WallAnims[MAX_WALL_ANIMS];        // Wall animations
  147. int Num_wall_anims;
  148. //--unused-- int walls_bm_num[MAX_WALL_ANIMS];
  149.  
  150. //door Doors[MAX_DOORS];                    //    Master doors array
  151.  
  152. active_door ActiveDoors[MAX_DOORS];
  153. int Num_open_doors;                        // Number of open doors
  154.  
  155. //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS];
  156.  
  157. //#define BM_FLAG_TRANSPARENT            1
  158. //#define BM_FLAG_SUPER_TRANSPARENT    2
  159.  
  160. #ifdef EDITOR
  161. char    Wall_names[7][10] = {
  162.     "NORMAL   ",
  163.     "BLASTABLE",
  164.     "DOOR     ",
  165.     "ILLUSION ",
  166.     "OPEN     ",
  167.     "CLOSED   ",
  168.     "EXTERNAL "
  169. };
  170. #endif
  171.  
  172. // This function determines whether the current segment/side is transparent
  173. //        1 = YES
  174. //        0 = NO
  175. int check_transparency( segment * seg, int side )
  176. {      
  177.     if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) {
  178.         if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT )
  179.             return 1;
  180.         else 
  181.             return 0;
  182.         }
  183.  
  184.     if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT )
  185.         return 1;
  186.     else
  187.         return 0;
  188. }
  189.  
  190. //-----------------------------------------------------------------
  191. // This function checks whether we can fly through the given side.
  192. //    In other words, whether or not we have a 'doorway'
  193. //     Flags:
  194. //        WID_FLY_FLAG                1
  195. //        WID_RENDER_FLAG            2
  196. //        WID_RENDPAST_FLAG            4
  197. //     Return values:
  198. //        WID_WALL                        2    // 0/1/0        wall    
  199. //        WID_TRANSPARENT_WALL        6    //    0/1/1        transparent wall
  200. //        WID_ILLUSORY_WALL            3    //    1/1/0        illusory wall
  201. //        WID_TRANSILLUSORY_WALL    7    //    1/1/1        transparent illusory wall
  202. //        WID_NO_WALL                    5    //    1/0/1        no wall, can fly through
  203. int wall_is_doorway ( segment * seg, int side )
  204. {
  205.     int flags, type;
  206.     int state;
  207. //--Covered by macro    // No child.
  208. //--Covered by macro    if (seg->children[side] == -1)
  209. //--Covered by macro        return WID_WALL;
  210.  
  211. //--Covered by macro    if (seg->children[side] == -2)
  212. //--Covered by macro        return WID_EXTERNAL_FLAG;
  213.  
  214. //--Covered by macro // No wall present.
  215. //--Covered by macro    if (seg->sides[side].wall_num == -1)
  216. //--Covered by macro        return WID_NO_WALL;
  217.  
  218.     Assert(seg-Segments>=0 && seg-Segments<=Highest_segment_index);
  219.     Assert(side>=0 && side<6);
  220.  
  221.     type = Walls[seg->sides[side].wall_num].type;
  222.     flags = Walls[seg->sides[side].wall_num].flags;
  223.  
  224.     if (type == WALL_OPEN)
  225.         return WID_NO_WALL;
  226.  
  227.     if (type == WALL_ILLUSION) {
  228.         if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF)
  229.             return WID_NO_WALL;
  230.         else {
  231.             if (check_transparency( seg, side))
  232.                 return WID_TRANSILLUSORY_WALL;
  233.              else
  234.                 return WID_ILLUSORY_WALL;
  235.         }
  236.     }
  237.  
  238.     if (type == WALL_BLASTABLE) {
  239.          if (flags & WALL_BLASTED)
  240.             return WID_TRANSILLUSORY_WALL;
  241.  
  242.         if (check_transparency( seg, side))
  243.             return WID_TRANSPARENT_WALL;
  244.         else
  245.             return WID_WALL;
  246.     }    
  247.     
  248.     if (flags & WALL_DOOR_OPENED)
  249.         return WID_TRANSILLUSORY_WALL;
  250.     
  251.     state = Walls[seg->sides[side].wall_num].state;
  252.     if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING))
  253.         return WID_TRANSPARENT_WALL;
  254.     
  255. // If none of the above flags are set, there is no doorway.
  256.     if (check_transparency( seg, side))
  257.         return WID_TRANSPARENT_WALL;
  258.     else
  259.         return WID_WALL; // There are children behind the door.
  260. }
  261.  
  262. #ifdef EDITOR
  263. //-----------------------------------------------------------------
  264. // Initializes all the walls (in other words, no special walls)
  265. void wall_init()
  266. {
  267.     int i;
  268.     
  269.     Num_walls = 0;
  270.     for (i=0;i<MAX_WALLS;i++) {
  271.         Walls[i].segnum = Walls[i].sidenum = -1;
  272.         Walls[i].type = WALL_NORMAL;
  273.         Walls[i].flags = 0;
  274.         Walls[i].hps = 0;
  275.         Walls[i].trigger = -1;
  276.         Walls[i].clip_num = -1;
  277.         Walls[i].linked_wall = -1;
  278.         }
  279.     Num_open_doors = 0;
  280.  
  281. }
  282.  
  283. //-----------------------------------------------------------------
  284. // Initializes one wall.
  285. void wall_reset(segment *seg, int side)
  286. {
  287.     int i;
  288.     
  289.     i = seg->sides[side].wall_num;
  290.  
  291.     if (i==-1) {
  292.         mprintf((0, "Resetting Illegal Wall\n"));
  293.         return;
  294.     }
  295.  
  296.     Walls[i].segnum = seg-Segments;
  297.     Walls[i].sidenum = side;
  298.     Walls[i].type = WALL_NORMAL;
  299.     Walls[i].flags = 0;
  300.     Walls[i].hps = 0;
  301.     Walls[i].trigger = -1;
  302.     Walls[i].clip_num = -1;
  303.     Walls[i].linked_wall = -1;
  304. }
  305. #endif
  306.  
  307. //set the tmap_num or tmap_num2 field for a wall/door
  308. void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num)
  309. {
  310.     wclip *anim = &WallAnims[anim_num];
  311.     int tmap = anim->frames[frame_num];
  312.  
  313.     if ( Newdemo_state==ND_STATE_PLAYBACK ) return;
  314.  
  315.     if (anim->flags & WCF_TMAP1)    {
  316.         seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap;
  317.         if ( Newdemo_state == ND_STATE_RECORDING )
  318.             newdemo_record_wall_set_tmap_num1(seg-Segments,side,csegp-Segments,cside,tmap);
  319.     } else    {
  320.         Assert(tmap!=0 && seg->sides[side].tmap_num2!=0);
  321.         seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap;
  322.         if ( Newdemo_state == ND_STATE_RECORDING )
  323.             newdemo_record_wall_set_tmap_num2(seg-Segments,side,csegp-Segments,cside,tmap);
  324.     }
  325. }
  326.  
  327.  
  328. // -------------------------------------------------------------------------------
  329. //when the wall has used all its hitpoints, this will destroy it
  330. void blast_blastable_wall(segment *seg, int side)
  331. {
  332.     int Connectside;
  333.     segment *csegp;
  334.     int a, n;
  335.  
  336.     Assert(seg->sides[side].wall_num != -1);
  337.  
  338.     csegp = &Segments[seg->children[side]];
  339.     Connectside = find_connect_side(seg, csegp);
  340.     Assert(Connectside != -1);
  341.  
  342.     kill_stuck_objects(seg->sides[side].wall_num);
  343.     kill_stuck_objects(csegp->sides[Connectside].wall_num);
  344.  
  345.     a = Walls[seg->sides[side].wall_num].clip_num;
  346.     n = WallAnims[a].num_frames;
  347.  
  348.     if (!(WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES))
  349.         wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1);
  350.  
  351.     Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED;
  352.     Walls[csegp->sides[Connectside].wall_num].flags |= WALL_BLASTED;
  353.  
  354.     //if this is an exploding wall, explode it
  355.     if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES)
  356.         explode_wall(seg-Segments,side);
  357. }
  358.  
  359.  
  360. //-----------------------------------------------------------------
  361. // Destroys a blastable wall.
  362. void wall_destroy(segment *seg, int side)
  363. {
  364.     Assert(seg->sides[side].wall_num != -1);
  365.     Assert(seg-Segments != 0);
  366.  
  367.     if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
  368.         blast_blastable_wall( seg, side );
  369.     else
  370.         Error("Hey bub, you are trying to destroy an indestructable wall.");
  371. }
  372.  
  373. //-----------------------------------------------------------------
  374. // Deteriorate appearance of wall. (Changes bitmap (paste-ons)) 
  375. void wall_damage(segment *seg, int side, fix damage)
  376. {
  377.     int a, i, n;
  378.  
  379.     if (seg->sides[side].wall_num == -1) {
  380.         mprintf((0, "Damaging illegal wall\n"));
  381.         return;
  382.     }
  383.  
  384.     if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE)
  385.         return;
  386.     
  387.     if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED))
  388.         {
  389.         int Connectside;
  390.         segment *csegp;
  391.  
  392.         csegp = &Segments[seg->children[side]];
  393.         Connectside = find_connect_side(seg, csegp);
  394.         Assert(Connectside != -1);
  395.         
  396.         Walls[seg->sides[side].wall_num].hps -= damage;
  397.         Walls[csegp->sides[Connectside].wall_num].hps -= damage;
  398.             
  399.         a = Walls[seg->sides[side].wall_num].clip_num;
  400.         n = WallAnims[a].num_frames;
  401.         
  402.         if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) {
  403.             blast_blastable_wall( seg, side );            
  404.             #ifdef NETWORK
  405.             if (Game_mode & GM_MULTI)
  406.                 multi_send_door_open(seg-Segments, side);
  407.             #endif
  408.         }
  409.         else
  410.             for (i=0;i<n;i++)
  411.                 if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*(n-i)/n) {
  412.                     wall_set_tmap_num(seg,side,csegp,Connectside,a,i);
  413.                 }
  414.         }
  415. }
  416.  
  417.  
  418. //-----------------------------------------------------------------
  419. // Opens a door 
  420. void wall_open_door(segment *seg, int side)
  421. {
  422.     wall *w;
  423.     active_door *d;
  424.     int Connectside;
  425.     segment *csegp;
  426.  
  427.     Assert(seg->sides[side].wall_num != -1);     //Opening door on illegal wall
  428.  
  429.     w = &Walls[seg->sides[side].wall_num];
  430.  
  431.     //kill_stuck_objects(seg->sides[side].wall_num);
  432.  
  433.     if (w->state == WALL_DOOR_OPENING)        //already opening
  434.         return;
  435.  
  436.     if (w->state == WALL_DOOR_WAITING)        //open, waiting to close
  437.         return;
  438.  
  439.     if (w->state != WALL_DOOR_CLOSED) {        //reuse door
  440.  
  441.         int i;
  442.     
  443.         d = NULL;
  444.  
  445.         for (i=0;i<Num_open_doors;i++) {        //find door
  446.  
  447.             d = &ActiveDoors[i];
  448.     
  449.             if (d->front_wallnum[0]==w-Walls || d->back_wallnum[0]==w-Walls || (d->n_parts==2 && (d->front_wallnum[1]==w-Walls || d->back_wallnum[1]==w-Walls)))
  450.                 break;
  451.         } 
  452.  
  453.         Assert(i<Num_open_doors);                //didn't find door!
  454.         Assert( d!=NULL ); // Get John!
  455.  
  456.         d->time = WallAnims[w->clip_num].play_time - d->time;
  457.  
  458.         if (d->time < 0)
  459.             d->time = 0;
  460.     
  461.     }
  462.     else {                                            //create new door
  463.         d = &ActiveDoors[Num_open_doors];
  464.         d->time = 0;
  465.         Num_open_doors++;
  466.         Assert( Num_open_doors < MAX_DOORS );
  467.     }
  468.  
  469.     w->state = WALL_DOOR_OPENING;
  470.  
  471.     // So that door can't be shot while opening
  472.     csegp = &Segments[seg->children[side]];
  473.     Connectside = find_connect_side(seg, csegp);
  474.     Assert(Connectside != -1);
  475.  
  476.     Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPENING;
  477.  
  478.     //kill_stuck_objects(csegp->sides[Connectside].wall_num);
  479.  
  480.     d->front_wallnum[0] = seg->sides[side].wall_num;
  481.     d->back_wallnum[0] = csegp->sides[Connectside].wall_num;
  482.  
  483.     Assert( seg-Segments != -1);
  484.  
  485. #ifndef SHAREWARE
  486.     if (Newdemo_state == ND_STATE_RECORDING) {
  487.         newdemo_record_door_opening(seg-Segments, side);
  488.     }
  489. #endif
  490.  
  491.     if (w->linked_wall != -1) {
  492.         wall *w2;
  493.         segment *seg2;
  494.  
  495.         w2        = &Walls[w->linked_wall];
  496.         seg2    = &Segments[w2->segnum];
  497.  
  498.         Assert(w2->linked_wall == seg->sides[side].wall_num);
  499.         //Assert(!(w2->flags & WALL_DOOR_OPENING  ||  w2->flags & WALL_DOOR_OPENED));
  500.  
  501.         w2->state = WALL_DOOR_OPENING;
  502.  
  503.         csegp = &Segments[seg2->children[w2->sidenum]];
  504.         Connectside = find_connect_side(seg2, csegp);
  505.         Assert(Connectside != -1);
  506.         Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_OPENING;
  507.  
  508.         d->n_parts = 2;
  509.         d->front_wallnum[1] = w->linked_wall;
  510.         d->back_wallnum[1] = csegp->sides[Connectside].wall_num;
  511.     }
  512.     else
  513.         d->n_parts = 1;
  514.  
  515.  
  516.     if ( Newdemo_state != ND_STATE_PLAYBACK )
  517.     {
  518.         // NOTE THE LINK TO ABOVE!!!!
  519.         vms_vector cp;
  520.         compute_center_point_on_side(&cp, seg, side );
  521.         if (WallAnims[w->clip_num].open_sound > -1 )
  522.             digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 );
  523.  
  524.     }
  525. }
  526.  
  527. //-----------------------------------------------------------------
  528. // This function closes the specified door and restores the closed
  529. //  door texture.  This is called when the animation is done
  530. void wall_close_door(int door_num)
  531. {
  532.     int p;
  533.     active_door *d;
  534.     int i;
  535.  
  536.     d = &ActiveDoors[door_num];
  537.  
  538.     for (p=0;p<d->n_parts;p++) {
  539.         wall *w;
  540.         int Connectside, side;
  541.         segment *csegp, *seg;
  542.     
  543.         w = &Walls[d->front_wallnum[p]];
  544.  
  545.         seg = &Segments[w->segnum];
  546.         side = w->sidenum;
  547.     
  548.         Assert(seg->sides[side].wall_num != -1);        //Closing door on illegal wall
  549.         
  550.         csegp = &Segments[seg->children[side]];
  551.         Connectside = find_connect_side(seg, csegp);
  552.         Assert(Connectside != -1);
  553.     
  554.         Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED;
  555.         Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSED;
  556.     
  557.         wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0);
  558.  
  559.     }
  560.     
  561.     for (i=door_num;i<Num_open_doors;i++)
  562.         ActiveDoors[i] = ActiveDoors[i+1];
  563.  
  564.     Num_open_doors--;
  565.  
  566. }
  567.  
  568.  
  569. //-----------------------------------------------------------------
  570. // Animates opening of a door.
  571. // Called in the game loop.
  572. void do_door_open(int door_num)
  573. {
  574.     int p;
  575.     active_door *d;
  576.  
  577.     Assert(door_num != -1);        //Trying to do_door_open on illegal door
  578.     
  579.     d = &ActiveDoors[door_num];
  580.  
  581.     for (p=0;p<d->n_parts;p++) {
  582.         wall *w;
  583.         int Connectside, side;
  584.         segment *csegp, *seg;
  585.         fix time_elapsed, time_total, one_frame;
  586.         int i, n;
  587.     
  588.         w = &Walls[d->front_wallnum[p]];
  589.         kill_stuck_objects(d->front_wallnum[p]);
  590.         kill_stuck_objects(d->back_wallnum[p]);
  591.  
  592.         seg = &Segments[w->segnum];
  593.         side = w->sidenum;
  594.     
  595.         Assert(seg->sides[side].wall_num != -1);        //Trying to do_door_open on illegal wall
  596.     
  597.         csegp = &Segments[seg->children[side]];
  598.         Connectside = find_connect_side(seg, csegp);
  599.         Assert(Connectside != -1);
  600.  
  601.         d->time += FrameTime;
  602.     
  603.         time_elapsed = d->time;
  604.         n = WallAnims[w->clip_num].num_frames;
  605.         time_total = WallAnims[w->clip_num].play_time;
  606.     
  607.         one_frame = time_total/n;    
  608.     
  609.         i = time_elapsed/one_frame;
  610.     
  611.         if (i < n)
  612.             wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
  613.     
  614.         if (i> n/2) {
  615.             Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED;
  616.             Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED;
  617.         }
  618.     
  619.         if (i >= n-1) {
  620.             wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1);
  621.  
  622.             // If our door is not automatic just remove it from the list.
  623.             if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) {
  624.                 for (i=door_num;i<Num_open_doors;i++)
  625.                     ActiveDoors[i] = ActiveDoors[i+1];
  626.                 Num_open_doors--;
  627.             }
  628.             else {
  629.  
  630.                 Walls[seg->sides[side].wall_num].state = WALL_DOOR_WAITING;
  631.                 Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING;
  632.  
  633.                 ActiveDoors[Num_open_doors].time = 0;    //counts up
  634.             }
  635.         }
  636.  
  637.     }
  638.  
  639. }
  640.  
  641. int check_poke(int objnum,int segnum,int side)
  642. {
  643.     object *obj = &Objects[objnum];
  644.  
  645.     //note: don't let objects with zero size block door
  646.  
  647.     if (obj->size && get_seg_masks(&obj->pos,segnum,obj->size).sidemask & (1<<side))
  648.         return 1;        //pokes through side!
  649.     else
  650.         return 0;        //does not!
  651.  
  652. }
  653.  
  654.  
  655. //-----------------------------------------------------------------
  656. // Animates and processes the closing of a door.
  657. // Called from the game loop.
  658. void do_door_close(int door_num)
  659. {
  660.     int p;
  661.     active_door *d;
  662.     wall *w;
  663.  
  664.     Assert(door_num != -1);        //Trying to do_door_open on illegal door
  665.     
  666.     d = &ActiveDoors[door_num];
  667.  
  668.     w = &Walls[d->front_wallnum[0]];
  669.  
  670.     //check for objects in doorway before closing
  671.     if (w->flags & WALL_DOOR_AUTO)
  672.         for (p=0;p<d->n_parts;p++) {
  673.             int Connectside, side;
  674.             segment *csegp, *seg;
  675.             int objnum;
  676.         
  677.             seg = &Segments[w->segnum];
  678.             side = w->sidenum;
  679.         
  680.             csegp = &Segments[seg->children[side]];
  681.             Connectside = find_connect_side(seg, csegp);
  682.             Assert(Connectside != -1);
  683.  
  684.             //go through each object in each of two segments, and see if
  685.             //it pokes into the connecting seg
  686.  
  687.             for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
  688.                 if (check_poke(objnum,seg-Segments,side))
  689.                     return;        //abort!
  690.  
  691.             for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next)
  692.                 if (check_poke(objnum,csegp-Segments,Connectside))
  693.                     return;        //abort!
  694.         }
  695.  
  696.     for (p=0;p<d->n_parts;p++) {
  697.         wall *w;
  698.         int Connectside, side;
  699.         segment *csegp, *seg;
  700.         fix time_elapsed, time_total, one_frame;
  701.         int i, n;
  702.     
  703.         w = &Walls[d->front_wallnum[p]];
  704.  
  705.         seg = &Segments[w->segnum];
  706.         side = w->sidenum;
  707.     
  708.         if (seg->sides[side].wall_num == -1) {
  709.             mprintf((0, "Trying to do_door_close on Illegal wall\n"));
  710.             return;
  711.         }
  712.     
  713.         //if here, must be auto door
  714.         Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO);        
  715.     
  716.         // Otherwise, close it.
  717.         csegp = &Segments[seg->children[side]];
  718.         Connectside = find_connect_side(seg, csegp);
  719.         Assert(Connectside != -1);
  720.     
  721.  
  722.         if ( Newdemo_state != ND_STATE_PLAYBACK )
  723.             // NOTE THE LINK TO ABOVE!!
  724.             if (p==0)    //only play one sound for linked doors
  725.                 if ( d->time==0 )    {        //first time
  726.                     vms_vector cp;
  727.                     compute_center_point_on_side(&cp, seg, side );
  728.                     if (WallAnims[w->clip_num].close_sound  > -1 )
  729.                         digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, seg-Segments, side, &cp, 0, F1_0 );
  730.                 }
  731.     
  732.         d->time += FrameTime;
  733.  
  734.         time_elapsed = d->time;
  735.         n = WallAnims[w->clip_num].num_frames;
  736.         time_total = WallAnims[w->clip_num].play_time;
  737.     
  738.         one_frame = time_total/n;    
  739.     
  740.         i = n-time_elapsed/one_frame-1;
  741.     
  742.         if (i < n/2) {
  743.             Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED;
  744.             Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED;
  745.         }
  746.     
  747.         // Animate door.
  748.         if (i > 0) {
  749.             wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i);
  750.  
  751.             Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING;
  752.             Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING;
  753.  
  754.             ActiveDoors[Num_open_doors].time = 0;        //counts up
  755.  
  756.         } else 
  757.             wall_close_door(door_num);
  758.     }
  759. }
  760.  
  761.  
  762. //-----------------------------------------------------------------
  763. // Turns off an illusionary wall (This will be used primarily for
  764. //  wall switches or triggers that can turn on/off illusionary walls.)
  765. void wall_illusion_off(segment *seg, int side)
  766. {
  767.     segment *csegp;
  768.     int cside;
  769.  
  770.     csegp = &Segments[seg->children[side]];
  771.     cside = find_connect_side(seg, csegp);
  772.     Assert(cside != -1);
  773.  
  774.     if (seg->sides[side].wall_num == -1) {
  775.         mprintf((0, "Trying to shut off illusion illegal wall\n"));
  776.         return;
  777.     }
  778.  
  779.     Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF;
  780.     Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF;
  781. }
  782.  
  783. //-----------------------------------------------------------------
  784. // Turns on an illusionary wall (This will be used primarily for
  785. //  wall switches or triggers that can turn on/off illusionary walls.)
  786. void wall_illusion_on(segment *seg, int side)
  787. {
  788.     segment *csegp;
  789.     int cside;
  790.  
  791.     csegp = &Segments[seg->children[side]];
  792.     cside = find_connect_side(seg, csegp);
  793.     Assert(cside != -1);
  794.  
  795.     if (seg->sides[side].wall_num == -1) {
  796.         mprintf((0, "Trying to turn on illusion illegal wall\n"));
  797.         return;
  798.     }
  799.  
  800.     Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF;
  801.     Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF;
  802. }
  803.  
  804. //    -----------------------------------------------------------------------------
  805. //    Allowed to open the normally locked special boss door if in multiplayer mode.
  806. int special_boss_opening_allowed(int segnum, int sidenum)
  807. {
  808.     if (Game_mode & GM_MULTI)
  809.         return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE);
  810.     else
  811.         return 0;
  812. }
  813.  
  814. //-----------------------------------------------------------------
  815. // Determines what happens when a wall is shot
  816. //returns info about wall.  see wall.h for codes
  817. //obj is the object that hit...either a weapon or the player himself
  818. //playernum is the number the player who hit the wall or fired the weapon,
  819. //or -1 if a robot fired the weapon
  820. int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj )
  821. {
  822.     wall    *w;
  823.     fix    show_message;
  824.  
  825.     Assert (seg-Segments != -1);
  826.  
  827.     // If it is not a "wall" then just return.
  828.     if ( seg->sides[side].wall_num < 0 )
  829.         return WHP_NOT_SPECIAL;
  830.  
  831.     w = &Walls[seg->sides[side].wall_num];
  832.  
  833.     if ( Newdemo_state == ND_STATE_RECORDING )
  834.         newdemo_record_wall_hit_process( seg-Segments, side, damage, playernum );
  835.  
  836.     if (w->type == WALL_BLASTABLE) {
  837.         wall_damage(seg, side, damage);
  838.         return WHP_BLASTABLE;
  839.     }
  840.  
  841.     if (playernum != Player_num)    //return if was robot fire
  842.         return WHP_NOT_SPECIAL;
  843.  
  844.     Assert( playernum > -1 );
  845.     
  846.     //    Determine whether player is facing door he hit.  If not, don't say negative
  847.     //    messages because he probably didn't intentionally hit the door.
  848.     if (obj->type == OBJ_PLAYER)
  849.         show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0);
  850.     else
  851.         show_message = 1;
  852.  
  853.     if (w->keys == KEY_BLUE)
  854.         if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) {
  855.             if ( playernum==Player_num )
  856.                 if (show_message)
  857.                     HUD_init_message("%s %s",TXT_BLUE,TXT_ACCESS_DENIED);
  858.             return WHP_NO_KEY;
  859.         }
  860.  
  861.     if (w->keys == KEY_RED)
  862.         if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) {
  863.             if ( playernum==Player_num )
  864.                 if (show_message)
  865.                     HUD_init_message("%s %s",TXT_RED,TXT_ACCESS_DENIED);
  866.             return WHP_NO_KEY;
  867.         }
  868.     
  869.     if (w->keys == KEY_GOLD)
  870.         if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) {
  871.             if ( playernum==Player_num )
  872.                 if (show_message)
  873.                     HUD_init_message("%s %s",TXT_YELLOW,TXT_ACCESS_DENIED);
  874.             return WHP_NO_KEY;
  875.         }
  876.  
  877.     if (w->type == WALL_DOOR)
  878.         if ((w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(seg-Segments, side)) ) {
  879.             if ( playernum==Player_num )
  880.                 if (show_message)
  881.                     HUD_init_message(TXT_CANT_OPEN_DOOR);
  882.             return WHP_NO_KEY;
  883.         }
  884.         else {
  885.             if (w->state != WALL_DOOR_OPENING)
  886.             {
  887.                 wall_open_door(seg, side);
  888.             #ifdef NETWORK
  889.                 if (Game_mode & GM_MULTI)
  890.                     multi_send_door_open(seg-Segments, side);
  891.             #endif
  892.             }
  893.             return WHP_DOOR;
  894.             
  895.         }
  896.  
  897.     return WHP_NOT_SPECIAL;        //default is treat like normal wall
  898. }
  899.  
  900. //-----------------------------------------------------------------
  901. // Opens doors/destroys wall/shuts off triggers.
  902. void wall_toggle(segment *seg, int side)
  903. {
  904.     int wall_num; 
  905.  
  906.     Assert( seg-Segments <= Highest_segment_index);
  907.     Assert( side < MAX_SIDES_PER_SEGMENT );
  908.  
  909.     wall_num = seg->sides[side].wall_num;
  910.  
  911.     if (wall_num == -1) {
  912.          mprintf((0, "Illegal wall_toggle\n"));
  913.         return;
  914.     }
  915.  
  916.     if ( Newdemo_state == ND_STATE_RECORDING )
  917.         newdemo_record_wall_toggle(seg-Segments, side );
  918.  
  919.     if (Walls[wall_num].type == WALL_BLASTABLE)
  920.         wall_destroy(seg, side);
  921.  
  922.     if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED))
  923.         wall_open_door(seg, side);
  924.  
  925. }
  926.  
  927.  
  928. //-----------------------------------------------------------------
  929. // Tidy up Walls array for load/save purposes.
  930. void reset_walls()
  931. {
  932.     int i;
  933.  
  934.     if (Num_walls < 0) {
  935.         mprintf((0, "Illegal Num_walls\n"));
  936.         return;
  937.     }
  938.  
  939.     for (i=Num_walls;i<MAX_WALLS;i++) {
  940.         Walls[i].type = WALL_NORMAL;
  941.         Walls[i].flags = 0;
  942.         Walls[i].hps = 0;
  943.         Walls[i].trigger = -1;
  944.         Walls[i].clip_num = -1;
  945.         }
  946. }
  947.  
  948. void wall_frame_process()
  949. {
  950.     int i;
  951.  
  952.     for (i=0;i<Num_open_doors;i++) {
  953.         active_door *d;
  954.         wall *w;
  955.  
  956.         d = &ActiveDoors[i];
  957.         w = &Walls[d->front_wallnum[0]];
  958.  
  959.         if (w->state == WALL_DOOR_OPENING)
  960.             do_door_open(i);
  961.         else if (w->state == WALL_DOOR_CLOSING)
  962.             do_door_close(i);
  963.         else if (w->state == WALL_DOOR_WAITING) {
  964.             d->time += FrameTime;
  965.             if (d->time > DOOR_WAIT_TIME) {
  966.                 w->state = WALL_DOOR_CLOSING;
  967.                 d->time = 0;
  968.             }
  969.         } 
  970.     } 
  971. }
  972.  
  973. int    Num_stuck_objects=0;
  974.  
  975. stuckobj    Stuck_objects[MAX_STUCK_OBJECTS];
  976.  
  977. //    An object got stuck in a door (like a flare).
  978. //    Add global entry.
  979. void add_stuck_object(object *objp, int segnum, int sidenum)
  980. {
  981.     int    i;
  982.     int    wallnum;
  983.  
  984.     wallnum = Segments[segnum].sides[sidenum].wall_num;
  985.  
  986.     if (wallnum != -1) {
  987.         if (Walls[wallnum].flags & WALL_BLASTED)
  988.             objp->flags |= OF_SHOULD_BE_DEAD;  
  989.  
  990.         for (i=0; i<MAX_STUCK_OBJECTS; i++) {
  991.             if (Stuck_objects[i].wallnum == -1) {
  992.                 Stuck_objects[i].wallnum = wallnum;
  993.                 Stuck_objects[i].objnum = objp-Objects;
  994.                 Stuck_objects[i].signature = objp->signature;
  995.                 // mprintf((0, "Added wall %i at index %i\n", wallnum, i));
  996.                 Num_stuck_objects++;
  997.                 break;
  998.             }
  999.         }
  1000.         if (i == MAX_STUCK_OBJECTS)
  1001.             mprintf((1, "Warning: Unable to add object %i which got stuck in wall %i to Stuck_objects\n", objp-Objects, wallnum));
  1002.     }
  1003.  
  1004.  
  1005.  
  1006. }
  1007.  
  1008. //    --------------------------------------------------------------------------------------------------
  1009. //    Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here.
  1010. //    Removes up to one/frame.
  1011. void remove_obsolete_stuck_objects(void)
  1012. {
  1013.     int    objnum;
  1014.  
  1015.     objnum = FrameCount % MAX_STUCK_OBJECTS;
  1016.  
  1017.     if (Stuck_objects[objnum].wallnum != -1)
  1018.         if ((Stuck_objects[objnum].wallnum == 0) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) {
  1019.             Num_stuck_objects--;
  1020.             Stuck_objects[objnum].wallnum = -1;
  1021.             // -- mprintf((0, "Removing obsolete stuck object %i\n", Stuck_objects[objnum].objnum));
  1022.         }
  1023.  
  1024. }
  1025.  
  1026. //    ----------------------------------------------------------------------------------------------------
  1027. //    Door with wall index wallnum is opening, kill all objects stuck in it.
  1028. void kill_stuck_objects(int wallnum)
  1029. {
  1030.     int    i;
  1031.  
  1032.     if (Num_stuck_objects == 0)
  1033.         return;
  1034.  
  1035.     Num_stuck_objects=0;
  1036.  
  1037.     for (i=0; i<MAX_STUCK_OBJECTS; i++)
  1038.         if (Stuck_objects[i].wallnum == wallnum) {
  1039.             if (Objects[Stuck_objects[i].objnum].type == OBJ_WEAPON) {
  1040.                 Objects[Stuck_objects[i].objnum].lifeleft = F1_0/4;
  1041.                 mprintf((0, "Removing object %i from wall %i\n", Stuck_objects[i].objnum, wallnum));
  1042.             } else
  1043.                 mprintf((0, "Warning: Stuck object of type %i, expected to be of type %i, see wall.c\n", Objects[Stuck_objects[i].objnum].type, OBJ_WEAPON));
  1044.                 // Int3();    //    What?  This looks bad.  Object is not a weapon and it is stuck in a wall!
  1045.             Stuck_objects[i].wallnum = -1;
  1046.         } else if (Stuck_objects[i].wallnum != -1)
  1047.             Num_stuck_objects++;
  1048. }
  1049.  
  1050. 
  1051.