home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_17 / venture.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-27  |  93.8 KB  |  3,859 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16. #include "graph3.h"  // include our graphics stuff
  17. #include "graph4.h"
  18. #include "graph6.h"
  19. #include "graph9.h"   // sound library
  20. #include "graph11.h"  // multitasking and keyboard interrupt driver
  21.  
  22. // P R O T O T Y P E S ///////////////////////////////////////////////////////
  23.  
  24. void Start_Explosion(int x,int y,int speed);
  25.  
  26. void Behind_Explosions(void);
  27.  
  28. void Erase_Explosions(void);
  29.  
  30. void Draw_Explosions(void);
  31.  
  32. void Animate_Explosions(void);
  33.  
  34. void Init_Explosions(void);
  35.  
  36. void Init_Monsters(void);
  37.  
  38. void Start_Monsters(int wx,int wy);
  39.  
  40. void Save_Monsters(int wx,int wy);
  41.  
  42. void Erase_Monsters(void);
  43.  
  44. void Behind_Monsters(void);
  45.  
  46. void Draw_Monsters(void);
  47.  
  48. int Start_Monster(int x,int y);
  49.  
  50. void Move_Monsters(void);
  51.  
  52. void Start_Arrow(int x,
  53.                  int y,
  54.                  int xv,
  55.                  int yv,
  56.                  int direction);
  57.  
  58. void Erase_Arrows(void);
  59.  
  60. void Behind_Arrows(void);
  61.  
  62. void Draw_Arrows(void);
  63.  
  64. void Move_Arrows(void);
  65.  
  66. void Init_Arrows(void);
  67.  
  68. void Start_Fireball(int x,
  69.                     int y,
  70.                     int xv,
  71.                     int yv);
  72.  
  73. void Erase_Fireballs(void);
  74.  
  75. void Behind_Fireballs(void);
  76.  
  77. void Draw_Fireballs(void);
  78.  
  79. void Move_Fireballs(void);
  80.  
  81. void Init_Fireballs(void);
  82.  
  83.  
  84. void Erase_Bat(void);
  85.  
  86. void Behind_Bat(void);
  87.  
  88. void Draw_Bat(void);
  89.  
  90. void Move_Bat(void);
  91.  
  92. void Control_Bat(void);
  93.  
  94. unsigned char Get_Pixel_DB(int x,int y);
  95.  
  96. int Initialize_Sound_System(void);
  97.  
  98. void Close_Sound_System(void);
  99.  
  100. void Play_Sound(int sound);
  101.  
  102. void Do_Intro(void);
  103.  
  104. // D E F I N E S /////////////////////////////////////////////////////////////
  105.  
  106. #define DEBUG           0   // turns on/off debug information
  107.  
  108. // defines for players weapon
  109.  
  110. #define ARROW_ALIVE           1 // state of a live arrow
  111. #define ARROW_DEAD            0 // state of a dead arrow
  112. #define NUM_ARROWS            3 // number of arrows that can be fired
  113.  
  114. // defines for monsters weapons
  115.  
  116. #define FIREBALL_ALIVE        1  // state of a live fireball
  117. #define FIREBALL_DEAD         0  // state of a dead fireball
  118. #define NUM_FIREBALLS         8  // number of fireballs that can be fired
  119.  
  120. #define FIREBALL_SPEED        6  // the velocity of a fireball
  121.  
  122. #define NUM_FIREBALL_FRAMES   3  // number of frames of animation in fireball
  123.                                  // sequence
  124. // general explosions
  125.  
  126. #define NUM_EXPLOSIONS       3  // number of explosions that can run at once
  127.  
  128. #define EXPLOSION_DEAD       0   // state of a dead explosion
  129. #define EXPLOSION_ALIVE      1   // state of a live explosion
  130.  
  131. #define RED_BASE 32              // start of the reds in default palette
  132.  
  133. // game area defines
  134.  
  135. #define CELL_ROWS       12  // number of rows in the cell world
  136. #define CELL_COLUMNS    14  // number of columns in the cell world
  137.  
  138. #define NUM_MONSTERS    8  // maximum number of monsters per screen
  139.  
  140. #define NUM_MONSTER_FRAMES 16 // number of animation frames
  141.  
  142. #define WORLD_ROWS      4   // the world is a 4x4 matrix of screens or a
  143. #define WORLD_COLUMNS   4   // total of 16 screens
  144.                             //
  145.                             //  .... player can be within 1 of 16 screens
  146.                             //  ....
  147.                             //  ....  '.' represents a screen
  148.                             //  ....
  149.  
  150. // defines for monsters
  151.  
  152. #define MONSTER_DEAD     0   // the monster is dead
  153. #define MONSTER_STILL    1   // the monster is sitting still thinking
  154. #define MONSTER_TURN     2   // the monster is sitting and turning
  155. #define MONSTER_CHASE    3   // the monster is chasing the player
  156. #define MONSTER_EVADE    4   // the monster is evading the player
  157. #define MONSTER_RANDOM   5   // the monster is moving in a random pre-selected
  158.                              // direction
  159.  
  160. #define MONSTER_DYING    6   // the monster is dying
  161.  
  162. // directions for the monsters
  163.  
  164. #define MONSTER_EAST     0
  165. #define MONSTER_WEST     1
  166. #define MONSTER_NORTH    2
  167. #define MONSTER_SOUTH    3
  168.  
  169. // defines for bat
  170.  
  171. #define BAT_DEAD        0   // the bat is dead, long live joker!
  172. #define BAT_WAVE        1   // the bat is doing a sinwave across the screen
  173. #define BAT_RANDOM      2   // the bat is moving in a random direction across
  174.                             // the screen
  175.  
  176. #define NUM_BAT_FRAMES  5   // number of bat animation frames
  177.  
  178. // player defines
  179.  
  180. #define PLAYER_DEAD     0
  181. #define PLAYER_ALIVE    1
  182. #define PLAYER_DYING    2
  183.  
  184. // direction of player
  185.  
  186. #define PLAYER_EAST     0
  187. #define PLAYER_WEST     1
  188. #define PLAYER_NORTH    2
  189. #define PLAYER_SOUTH    3
  190.  
  191. // bitmap id's for special objects
  192.  
  193. #define FLOOR_1_ID      32
  194. #define FLOOR_2_ID      33
  195.  
  196. #define SILVER_ID       34
  197. #define GOLD_ID         35
  198. #define POTION_ID       36
  199. #define FOOD_ID         37
  200. #define ARROWS_ID       38
  201. #define EXIT_ID         39
  202. #define DAGGER_ID       40
  203.  
  204. // sound system defines
  205.  
  206. #define NUM_SOUNDS           16     // number of sounds in system
  207.  
  208. #define SOUND_HURT           0      // archer is hurt
  209. #define SOUND_MDIE           1      // a monster is dying
  210. #define SOUND_HEALTH         2      // low health
  211. #define SOUND_MFIRE          3      // a monster firing
  212. #define SOUND_MONEY          4      // the sound of money
  213. #define SOUND_EAT            5      // archer eating
  214. #define SOUND_FARROW         6      // finding arrows
  215. #define SOUND_POTION         7      // finding a potion
  216. #define SOUND_ARROW          8      // an arrow hiting a monster
  217. #define SOUND_BOW            9      // the sound of the bow
  218. #define SOUND_BAT            10     // the sound of the bat
  219. #define SOUND_INTRO          11     // the introduction
  220. #define SOUND_DAGGER         12     // player finding dagger
  221. #define SOUND_END            13     // it's all over
  222. #define SOUND_DEATH          14     // the player being killed
  223. #define SOUND_GOAL           15
  224.  
  225. #define SOUND_DEFAULT_PORT   0x220  // default sound port for sound blaster
  226. #define SOUND_DEFAULT_INT    5      // default interrupt
  227.  
  228. // M A C R O S //////////////////////////////////////////////////////////////
  229.  
  230. #define SET_SPRITE_SIZE(w,h) {sprite_width=w; sprite_height=h;}
  231.  
  232. // S T R U C T U R E S ///////////////////////////////////////////////////////
  233.  
  234.  
  235. // this is used to track the position of a monster and it's state when the
  236. // screen is first paged to and to recall when the screen is left and
  237. // revisted so that mosnters that are killed stay dead and so forth
  238.  
  239. typedef struct monster_pos_typ
  240.         {
  241.  
  242.         int state;  // state of monster
  243.         int x,y;    // position of the monster is pixel coordinates
  244.  
  245.         } monster_pos, *monster_pos_ptr;
  246.  
  247. // this is the data structure that holds a single screen
  248.  
  249. typedef struct screen_typ
  250.         {
  251.  
  252.         int cells[CELL_ROWS][CELL_COLUMNS];  // the data storage for cell id's
  253.  
  254.         int num_monsters;                    // number of monsters in the screen
  255.  
  256.         monster_pos positions[NUM_MONSTERS]; // this holds the state and positions
  257.                                              // of the monsters on entry and exit
  258.  
  259.         } screen, *screen_ptr;
  260.  
  261. // typedef for a projectile
  262.  
  263. typedef struct projectile_typ
  264.         {
  265.         int x;                   // x position
  266.         int y;                   // y position
  267.         int xv;                  // x velocity
  268.         int yv;                  // y velocity
  269.         int state;               // the state of the particle
  270.         int counter;             // use for counting
  271.         int threshold;           // the counters threshold
  272.  
  273.         int counter_2;
  274.         int threshold_2;
  275.  
  276.         sprite object;           // the projectile sprite
  277.  
  278.         } projectile, *projectile_ptr;
  279.  
  280. // typedef for the monster
  281.  
  282. typedef struct monster_typ
  283.         {
  284.         int x;                   // x position
  285.         int y;                   // y position
  286.         int xv;                  // x velocity
  287.         int yv;                  // y velocity
  288.         int state;               // the state of the monster
  289.         int direction;
  290.         int counter;             // use for counting
  291.         int threshold;           // the counters threshold
  292.  
  293.         int counter_2;
  294.         int threshold_2;
  295.  
  296.         int counter_3;
  297.         int threshold_3;
  298.  
  299.         sprite object;           // the monster sprite
  300.  
  301.         } monster, *monster_ptr;
  302.  
  303. // G L O B A L S  ////////////////////////////////////////////////////////////
  304.  
  305. pcx_picture imagery_pcx,      // the game imagery
  306.             background_pcx,   // the backdrop
  307.             intro_pcx;        // the introduction screen
  308.  
  309. // the sprites used in the game
  310.  
  311. sprite player,                // the player
  312.        wall_1,                // holds the blue walls bitmaps
  313.        wall_2,                // holds the green walls bitmaps
  314.        floors;                // holds the floor bitmaps
  315.  
  316.  
  317. sprite explosions[NUM_EXPLOSIONS];   // the array of explosions
  318.  
  319. projectile arrows[NUM_ARROWS];   // the array of arrows in the world
  320.  
  321. projectile fireballs[NUM_FIREBALLS];  // the array of fireballs in the world
  322.  
  323. projectile bat;                  // the bat
  324.  
  325. monster monsters[NUM_MONSTERS];  // the monsters
  326.  
  327. // velocity look up tables for players arrow, east, west, north and south
  328.  
  329. int arrow_vel_x[4] = {6,-6,0,0};
  330. int arrow_vel_y[4] = {0,0,-6,6};
  331.  
  332. int cos_look[320];   // cosine lookup table
  333.  
  334. int sqrt_table[400]; // square root look up
  335.  
  336. // players inventory
  337.  
  338. long players_score = 0;    // initial score
  339.  
  340. int players_dir    = PLAYER_SOUTH;  // initial direction of player
  341.  
  342. int silver_pieces  = 0;    // amount of silver pieces player has
  343.  
  344. int gold_pieces    = 0;    // amount of gold pieces player has
  345.  
  346. int number_potions = 0;    // number of magical potions (smart bombs)
  347.  
  348. int health         = 100;   // start health off at 100 percent
  349.  
  350. int num_arrows     = 50;   // player has 50 arrows to start with
  351.  
  352. int dagger_found   = 0;    // flags if the player has found the dagger
  353.  
  354. int weak_counter   = 350;  // used to count how many cycles before
  355.                            // verbal health message is repeated
  356.  
  357. int start_death    = 0;    // flags if players death sequence has started
  358.  
  359.  
  360. // the world
  361.  
  362. screen world[WORLD_ROWS][WORLD_COLUMNS];  // the game world
  363.  
  364. int screen_x      = 0,        // current active screen coordinates
  365.     screen_y      = 0,
  366.     old_screen_x  = 0,        // last active screen coords
  367.     old_screen_y  = 0,
  368.     screen_change = 0;        // has there been a screen change
  369.  
  370. // the sound system variables
  371.  
  372. char far *sound_fx[NUM_SOUNDS];           // pointers to the voc files
  373. unsigned char sound_lengths[NUM_SOUNDS];  // lengths of the voc files
  374.  
  375. int sound_available = 0;                  // flags if sound is available
  376.  
  377. int sound_port = SOUND_DEFAULT_PORT;      // default sound port
  378. int sound_int  = SOUND_DEFAULT_INT;       // default sound interrupt
  379.  
  380. // F U N C T I O N S //////////////////////////////////////////////////////////
  381.  
  382. void Start_Explosion(int x,int y,int speed)
  383. {
  384. // this function stars a generic explosion
  385.  
  386. int index;
  387.  
  388. SET_SPRITE_SIZE(16,16);
  389.  
  390. // scan for a useable explosion
  391.  
  392. for (index=0; index<NUM_EXPLOSIONS; index++)
  393.     {
  394.  
  395.     if (explosions[index].state == EXPLOSION_DEAD)
  396.        {
  397.  
  398.        // set up fields
  399.  
  400.        explosions[index].state      = EXPLOSION_ALIVE;
  401.        explosions[index].x          = x;
  402.        explosions[index].y          = y;
  403.        explosions[index].curr_frame = 0;
  404.        explosions[index].anim_speed = speed;
  405.        explosions[index].anim_clock = 0;
  406.  
  407.        // scan background to be safe
  408.  
  409.        Behind_Sprite_DB((sprite_ptr)&explosions[index]);
  410.  
  411.        break; // exit loop
  412.  
  413.        } // end if found a good one
  414.  
  415.     } // end for index
  416.  
  417. } // end Start_Explosion
  418.  
  419. /////////////////////////////////////////////////////////////////////////////
  420.  
  421. void Behind_Explosions(void)
  422. {
  423.  
  424. // this function scans under the explosions
  425.  
  426. int index;
  427.  
  428. SET_SPRITE_SIZE(16,16);
  429.  
  430. // scan for a running explosions
  431.  
  432. for (index=0; index<NUM_EXPLOSIONS; index++)
  433.     {
  434.  
  435.     if (explosions[index].state == EXPLOSION_ALIVE)
  436.        {
  437.        Behind_Sprite_DB((sprite_ptr)&explosions[index]);
  438.  
  439.        } // end if found a good one
  440.  
  441.     } // end for index
  442.  
  443. } // end Behind_Explosions
  444.  
  445. /////////////////////////////////////////////////////////////////////////////
  446.  
  447. void Erase_Explosions(void)
  448. {
  449. // this function erases all the current explosions
  450.  
  451. int index;
  452.  
  453. SET_SPRITE_SIZE(16,16);
  454.  
  455. // scan for a useable explosion
  456.  
  457. for (index=0; index<NUM_EXPLOSIONS; index++)
  458.     {
  459.  
  460.     if (explosions[index].state == EXPLOSION_ALIVE)
  461.        {
  462.        Erase_Sprite_DB((sprite_ptr)&explosions[index]);
  463.  
  464.        } // end if found a good one
  465.  
  466.     } // end for index
  467.  
  468. } // end Erase_Explosions
  469.  
  470. /////////////////////////////////////////////////////////////////////////////
  471.  
  472. void Draw_Explosions(void)
  473. {
  474. // this function draws the explosion
  475.  
  476. int index;
  477.  
  478. SET_SPRITE_SIZE(16,16);
  479.  
  480. // scan for a useable explosion
  481.  
  482. for (index=0; index<NUM_EXPLOSIONS; index++)
  483.     {
  484.  
  485.     // make sure this explosion is alive
  486.  
  487.     if (explosions[index].state == EXPLOSION_ALIVE)
  488.        {
  489.  
  490.        Draw_Sprite_DB((sprite_ptr)&explosions[index]);
  491.  
  492.        } // end if found a good one
  493.  
  494.     } // end for index
  495.  
  496. } // end Draw_Explosions
  497.  
  498. /////////////////////////////////////////////////////////////////////////////
  499.  
  500. void Animate_Explosions(void)
  501. {
  502. // this function steps the explosion thru the frames of animation
  503. int index;
  504.  
  505. // scan for a useable explosion
  506.  
  507. for (index=0; index<NUM_EXPLOSIONS; index++)
  508.     {
  509.     // test if explosion is alive
  510.     if (explosions[index].state == EXPLOSION_ALIVE)
  511.        {
  512.        // test if it's time to change frames
  513.  
  514.        if (++explosions[index].anim_clock == explosions[index].anim_speed)
  515.           {
  516.           // is the explosion over?
  517.  
  518.           if (++explosions[index].curr_frame == 4)
  519.              explosions[index].state = EXPLOSION_DEAD;
  520.  
  521.           // reset animation clock for future
  522.  
  523.           explosions[index].anim_clock = 0;
  524.  
  525.           } // end if time ti change frames
  526.  
  527.        } // end if found a good one
  528.  
  529.     } // end for index
  530.  
  531. } // end Animate_Explosions
  532.  
  533. //////////////////////////////////////////////////////////////////////////////
  534.  
  535. void Init_Explosions(void)
  536. {
  537. // reset all explosions
  538.  
  539. int index;
  540.  
  541. for (index=0; index<NUM_EXPLOSIONS; index++)
  542.     explosions[index].state = EXPLOSION_DEAD;
  543.  
  544. } // Init_Explosions
  545.  
  546. //////////////////////////////////////////////////////////////////////////////
  547.  
  548. void Draw_Sprite_DBM(sprite_ptr sprite)
  549. {
  550.  
  551. // this function draws a sprite on the screen row by row very quickly
  552. // note the use of shifting to implement multplication
  553. // also it is used as a special effect, the sprite drawn is melted by
  554. // randomly selecting red pixels
  555.  
  556. char far *work_sprite;
  557. int work_offset=0,offset,x,y;
  558. unsigned char data;
  559.  
  560. // alias a pointer to sprite for ease of access
  561.  
  562. work_sprite = sprite->frames[sprite->curr_frame];
  563.  
  564. // compute offset of sprite in video buffer
  565.  
  566. offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  567.  
  568. for (y=0; y<sprite_height; y++)
  569.     {
  570.     // copy the next row into the double buffer using memcpy for speed
  571.  
  572.     for (x=0; x<sprite_width; x++)
  573.         {
  574.  
  575.         // test for transparent pixel i.e. 0, if not transparent then draw
  576.  
  577.         if ((work_sprite[work_offset+x]))
  578.              double_buffer[offset+x] = RED_BASE+rand()%32;
  579.  
  580.         } // end for x
  581.  
  582.     // move to next line in double buffer and in sprite bitmap buffer
  583.  
  584.     offset      += SCREEN_WIDTH;
  585.     work_offset += sprite_width;
  586.  
  587.     } // end for y
  588.  
  589. } // end Draw_Sprite_DBM
  590.  
  591. /////////////////////////////////////////////////////////////////////////////
  592.  
  593. void Create_Lookups(void)
  594. {
  595. // this function creates all the look up tables
  596.  
  597. int index; // loop index
  598.  
  599. // create cosine look up table
  600.  
  601. for (index=0; index<320; index++)
  602.     cos_look[index] = (int)(4*cos(3.14159*5*(float)index/180));
  603.  
  604. // create sqrt table
  605.  
  606. for (index=0; index<400; index++)
  607.     sqrt_table[index] = (int)((float).5 + (float)sqrt(index));
  608.  
  609. } // end Create_Lookups
  610.  
  611. ///////////////////////////////////////////////////////////////////////////////
  612.  
  613. void Erase_Monsters(void)
  614. {
  615.  
  616. // this function indexes through all the monsters and if they are active
  617. // erases them by replacing the background color that was under them
  618.  
  619. int index;
  620.  
  621. // set sprite size for engine
  622.  
  623. SET_SPRITE_SIZE(16,16);
  624.  
  625. for (index=0; index<NUM_MONSTERS; index++)
  626.     {
  627.  
  628.     // is this monster active
  629.  
  630.     if (monsters[index].state != MONSTER_DEAD)
  631.        {
  632.  
  633.        // extract proper parameters
  634.  
  635.        monsters[index].object.x = monsters[index].x;
  636.        monsters[index].object.y = monsters[index].y;
  637.  
  638.        // erase the sprite
  639.  
  640.        Erase_Sprite_DB((sprite_ptr)&monsters[index].object);
  641.  
  642.        } // end if alive
  643.  
  644.     } // end for index
  645.  
  646. } // end Erase_Monsters
  647.  
  648. /////////////////////////////////////////////////////////////////////////////
  649.  
  650. void Behind_Monsters(void)
  651. {
  652.  
  653. // this function indexes through all the monsters and if they are active
  654. // scans the background under them
  655.  
  656. int index;
  657.  
  658. // set sprite size for engine
  659.  
  660. SET_SPRITE_SIZE(16,16);
  661.  
  662. for (index=0; index<NUM_MONSTERS; index++)
  663.     {
  664.  
  665.     // is this monster active
  666.  
  667.     if (monsters[index].state != MONSTER_DEAD)
  668.        {
  669.  
  670.        // extract proper parameters
  671.  
  672.        monsters[index].object.x = monsters[index].x;
  673.        monsters[index].object.y = monsters[index].y;
  674.  
  675.        // scan behind the sprite
  676.  
  677.        Behind_Sprite_DB((sprite_ptr)&monsters[index].object);
  678.  
  679.        } // end if alive
  680.  
  681.     } // end for index
  682.  
  683. } // end Behind_Monsters
  684.  
  685. /////////////////////////////////////////////////////////////////////////////
  686.  
  687. void Draw_Monsters(void)
  688. {
  689.  
  690. // this function indexes through all the monsters and if they are active
  691. // draws them
  692.  
  693. int index;
  694.  
  695. // set sprite size for engine
  696.  
  697. SET_SPRITE_SIZE(16,16);
  698.  
  699. for (index=0; index<NUM_MONSTERS; index++)
  700.     {
  701.  
  702.     // is this monster active
  703.  
  704.     if (monsters[index].state != MONSTER_DEAD)
  705.        {
  706.  
  707.        // extract proper parameters
  708.  
  709.        monsters[index].object.x = monsters[index].x;
  710.        monsters[index].object.y = monsters[index].y;
  711.  
  712.        // draw the sprite (test for dying case i.e. melting blitter)
  713.  
  714.        if (monsters[index].state==MONSTER_DYING)
  715.           Draw_Sprite_DBM((sprite_ptr)&monsters[index].object);
  716.        else
  717.           Draw_Sprite_DB((sprite_ptr)&monsters[index].object);
  718.  
  719.        } // end if alive
  720.  
  721.     } // end for index
  722.  
  723. } // end Draw_Monsters
  724.  
  725. /////////////////////////////////////////////////////////////////////////////
  726.  
  727. void Move_Monsters(void)
  728. {
  729. // this function moves all the monsters
  730.  
  731. // defines the animation cells to be used when the monster is spining
  732.  
  733. static int spin_table[4] = {8,4,8,0};
  734.  
  735. int index,          // loop index
  736.     change_state,   // flags if a state change is needed for the current monster
  737.     mx,my,          // position of monster
  738.     mdx,mdy,        // amount to move monster
  739.     pdx,pdy,        // delta from player
  740.     cell_x,cell_y,  // cell positions
  741.     cell_id,        // cell id number
  742.     animate=0;      // tracks if its time to animate monster
  743.  
  744. float radicand;
  745.  
  746. // scan through monster array and test for actives
  747.  
  748. for (index=0; index<NUM_MONSTERS; index++)
  749.     {
  750.     // is this a live one
  751.  
  752.     if (monsters[index].state != MONSTER_DEAD)
  753.        {
  754.  
  755.        // reset state change flag
  756.  
  757.        change_state = 0;
  758.  
  759.        mdx=mdy=0;
  760.  
  761.        // process monster
  762.  
  763.        switch(monsters[index].state)
  764.              {
  765.  
  766.              case MONSTER_DYING:
  767.  
  768.              case MONSTER_STILL: // do nothing
  769.                   {
  770.  
  771.                   // is it time to change state
  772.  
  773.                   // do nothing!
  774.  
  775.                   mx = monsters[index].x+8;
  776.                   my = monsters[index].y+14;
  777.  
  778.                   mdx=mdy=0;
  779.  
  780.                   // reset animate flag
  781.  
  782.                   animate=0;
  783.  
  784.                   } break;
  785.  
  786.              case MONSTER_TURN: // turn the monster around
  787.                   {
  788.  
  789.  
  790.                   if (++monsters[index].counter >= monsters[index].threshold)
  791.                      {
  792.                      // reset counter
  793.  
  794.                      monsters[index].counter = 0;
  795.  
  796.                      // increment frame to make monster look like it's spinning
  797.  
  798.                      monsters[index].object.curr_frame
  799.                      = spin_table[monsters[index].counter_3];
  800.  
  801.                      if (++monsters[index].counter_3 > 3)
  802.                         monsters[index].counter_3 = 0;
  803.  
  804.                      } // end if end change frames
  805.  
  806.                   mx = monsters[index].x+8;
  807.                   my = monsters[index].y+14;
  808.  
  809.                   mdx=mdy=0;
  810.  
  811.                   // reset animate flag
  812.  
  813.                   animate=0;
  814.  
  815.                   } break;
  816.  
  817.  
  818.              case MONSTER_CHASE: // the monster is tracking the player
  819.                   {
  820.  
  821.                   mx = monsters[index].x+8;
  822.                   my = monsters[index].y+14;
  823.  
  824.                   // is is time to process monster
  825.  
  826.                   if (++monsters[index].counter >= monsters[index].threshold)
  827.                      {
  828.                      // reset counter
  829.  
  830.                      monsters[index].counter = 0;
  831.  
  832.                      if (player.x+8 > mx)
  833.                         mdx=2;
  834.                      else
  835.                      if (player.x+8 < mx)
  836.                         mdx=-2;
  837.  
  838.                      if (player.y+14 > my)
  839.                         mdy=2;
  840.                      else
  841.                      if (player.y+14 < my)
  842.                         mdy=-2;
  843.  
  844.                      // set animate flag
  845.  
  846.                      animate=1;
  847.  
  848.                      } // end if end process monster
  849.  
  850.                   } break;
  851.  
  852.              case MONSTER_EVADE: // the monster is evading the player
  853.                   {
  854.                   // obtain center of monster
  855.  
  856.                   mx = monsters[index].x+8;
  857.                   my = monsters[index].y+14;
  858.  
  859.                   // is is time to process monster
  860.  
  861.                   if (++monsters[index].counter >= monsters[index].threshold)
  862.                      {
  863.                      // reset counter
  864.  
  865.                      monsters[index].counter = 0;
  866.  
  867.                      // test where player is relative to monster and create
  868.                      // trajectory vector
  869.  
  870.                      if (player.x+8 < mx)
  871.                         mdx=2;
  872.                      else
  873.                      if (player.x+8 > mx)
  874.                         mdx=-2;
  875.                      else
  876.                         mdx=0;
  877.  
  878.                      if (player.y+14 < my)
  879.                         mdy=2;
  880.                      else
  881.                      if (player.y+14 > my)
  882.                         mdy=-2;
  883.                      else
  884.                         mdy=0;
  885.  
  886.                      // set animate flag
  887.  
  888.                      animate=1;
  889.  
  890.                      } // end if process monster
  891.  
  892.                   } break;
  893.  
  894.              case MONSTER_RANDOM: // the monster has selected a random direction
  895.                   {
  896.                   // obtain center of monster
  897.  
  898.                   mx = monsters[index].x+8;
  899.                   my = monsters[index].y+14;
  900.  
  901.                   mdx=mdy=0;
  902.  
  903.                   // is is time to process monster
  904.  
  905.                   if (++monsters[index].counter >= monsters[index].threshold)
  906.                      {
  907.                      // reset counter
  908.  
  909.                      monsters[index].counter = 0;
  910.  
  911.                      // compute translation factors
  912.  
  913.                      mdx = monsters[index].xv;
  914.                      mdy = monsters[index].yv;
  915.  
  916.                      // set animate flag
  917.  
  918.                      animate=1;
  919.  
  920.                      } // end if end process monster
  921.  
  922.                   } break;
  923.  
  924.              default: break;
  925.  
  926.              } // end switch
  927.  
  928.  
  929.        // try and fire a fireball
  930.  
  931.        if (rand()%60==1)
  932.           {
  933.  
  934.           // compute trajectory vector
  935.  
  936.           pdx = player.x - monsters[index].x;
  937.           pdy = player.y - monsters[index].y;
  938.  
  939.           // make sure the monster is not on top of player this would cause
  940.           // a zero in the denominator and a pole to infinity
  941.  
  942.           if ((pdx+pdy)>0)
  943.              {
  944.  
  945.              // normalize vector and multiple by speed
  946.  
  947.              radicand = (float)pdx*(float)pdx+(float)pdy*(float)pdy;
  948.  
  949.              pdx = (int)(.5+((float)FIREBALL_SPEED*(float)pdx)/sqrt(radicand));
  950.              pdy = (int)(.5+((float)FIREBALL_SPEED*(float)pdy)/sqrt(radicand));
  951.  
  952.              // using computed trajectory vector throw a fireball at
  953.              // player
  954.  
  955.              Start_Fireball(monsters[index].x+8,monsters[index].y+8,
  956.                             pdx,pdy);
  957.  
  958.             } // end if ok to start a fireball
  959.  
  960.           } // end if fire a fireball
  961.  
  962.        // do horizontal translation
  963.  
  964.        mx+=mdx;
  965.        monsters[index].x+=mdx;
  966.  
  967.        // test if a object has been hit
  968.  
  969.        cell_x = mx >> 4;
  970.        cell_y = my >> 4;
  971.  
  972.        cell_id = world[screen_y][screen_x].cells[cell_y][cell_x];
  973.  
  974.        // test for horizontal collisions
  975.  
  976.        if (mx>224-8 || mx < 8 || cell_id < 32)
  977.           {
  978.           mx-=mdx;
  979.           monsters[index].x-=mdx;
  980.           }
  981.  
  982.        // do vertical translation
  983.  
  984.        my+=mdy;
  985.        monsters[index].y+=mdy;
  986.  
  987.        // test if a object has been hit
  988.  
  989.        cell_x = mx >> 4;
  990.        cell_y = my >> 4;
  991.  
  992.        cell_id = world[screen_y][screen_x].cells[cell_y][cell_x];
  993.  
  994.        // test for horizontal collisions
  995.  
  996.        if (my>180-8 || my < 8 || cell_id < 32)
  997.           {
  998.           my-=mdy;
  999.           monsters[index].y-=mdy;
  1000.           } // end if a horizontal collision
  1001.  
  1002.        // test if the monster is on top of the player
  1003.  
  1004.        if ( monsters[index].state!=MONSTER_DYING &&
  1005.             (mx > player.x) && (mx < player.x+16) &&
  1006.             (my > player.y) && (my < player.y+16) )
  1007.           {
  1008.           // hurt player a little
  1009.  
  1010.           if (--health<0)
  1011.              health=0;
  1012.  
  1013.           // play a hurt sound
  1014.  
  1015.           if (rand()%5==1)
  1016.              Play_Sound(SOUND_HURT);
  1017.  
  1018.           } // end if player is bitting player
  1019.  
  1020.        // do animation of monster
  1021.  
  1022.        if (animate)
  1023.           {
  1024.  
  1025.           // move to next frame in sequence depending on direction of motion
  1026.  
  1027.           if ((mdx!=0 && mdy!=0) || (mdx!=0 && mdy==0 ))
  1028.              {
  1029.  
  1030.              if (mdx>0)
  1031.                 {
  1032.                 // display next frame of right motion
  1033.  
  1034.                 if (++monsters[index].object.curr_frame > 3)
  1035.                    monsters[index].object.curr_frame = 0;
  1036.                 } // end if moving right
  1037.              else
  1038.                 {
  1039.                 // monster moving left
  1040.  
  1041.                 if (++monsters[index].object.curr_frame > 7)
  1042.                    monsters[index].object.curr_frame = 4;
  1043.  
  1044.                 } // end else left motion
  1045.  
  1046.              } // end if diagonal motion
  1047.           else
  1048.           if (mdy!=0 && mdx==0)
  1049.              {
  1050.  
  1051.              if (mdy>0)
  1052.                 {
  1053.                 // display next frame of downward motion
  1054.  
  1055.                 if (++monsters[index].object.curr_frame > 11)
  1056.                    monsters[index].object.curr_frame = 8;
  1057.  
  1058.                 } // end if moving down
  1059.              else
  1060.                 {
  1061.                 // monster moving up
  1062.  
  1063.                 if (++monsters[index].object.curr_frame > 15)
  1064.                    monsters[index].object.curr_frame = 12;
  1065.  
  1066.                 } // end else upward motion
  1067.  
  1068.              } // end if vertical
  1069.  
  1070.           } // end if time to animate
  1071.  
  1072.        // test if a state change is needed
  1073.  
  1074.        if (++monsters[index].counter_2 >= monsters[index].threshold_2)
  1075.           {
  1076.  
  1077.           // we need to change state
  1078.  
  1079.           change_state=1;
  1080.  
  1081.           } // end if need to change state
  1082.  
  1083.        // test for a pre-emptive collision
  1084.  
  1085.  
  1086.        // test if there was a state change
  1087.  
  1088.        if (change_state)
  1089.           {
  1090.  
  1091.           // test if last state was dying
  1092.  
  1093.           if (monsters[index].state==MONSTER_DYING)
  1094.              {
  1095.              // kill the monster
  1096.  
  1097.              monsters[index].state=MONSTER_DEAD;
  1098.  
  1099.              continue;
  1100.  
  1101.              } // end if kill monster
  1102.  
  1103.           monsters[index].object.curr_frame = 8;
  1104.  
  1105.           // select a new state, note the use of random numbers to create
  1106.           // a probability density
  1107.  
  1108.           switch(rand()%10)
  1109.                 {
  1110.  
  1111.                 case 0: // 10% chance of monster still
  1112.                      {
  1113.                      monsters[index].xv           = 0;
  1114.                      monsters[index].yv           = 0;
  1115.                      monsters[index].state        = MONSTER_STILL;
  1116.                      monsters[index].direction    = 0;
  1117.                      monsters[index].counter      = 0;
  1118.                      monsters[index].threshold    = 1 + rand()%2;
  1119.                      monsters[index].counter_2    = 0;
  1120.                      monsters[index].threshold_2  = 10 + rand()%10;
  1121.                      monsters[index].object.curr_frame = 8;
  1122.  
  1123.                      } break;
  1124.  
  1125.                 case 1: // 10% chance of monster turn
  1126.                      {
  1127.                      monsters[index].xv           = 0;
  1128.                      monsters[index].yv           = 0;
  1129.                      monsters[index].state        = MONSTER_TURN;
  1130.                      monsters[index].direction    = 0;
  1131.                      monsters[index].counter      = 0;
  1132.                      monsters[index].threshold    = 3 + rand()%3;
  1133.                      monsters[index].counter_2    = 0;
  1134.                      monsters[index].counter_3    = 0;
  1135.                      monsters[index].threshold_2  = 20 + rand()%20;
  1136.                      monsters[index].object.curr_frame = 8;
  1137.  
  1138.                      } break;
  1139.  
  1140.  
  1141.                 case 2: // 20% chance of monster random
  1142.                 case 3:
  1143.                      {
  1144.  
  1145.                      // select a direction
  1146.  
  1147.                      switch((monsters[index].direction = rand()%4))
  1148.                            {
  1149.  
  1150.                            case MONSTER_EAST:
  1151.                                 {
  1152.                                 monsters[index].xv = 2 + 2*rand()%2;
  1153.  
  1154.                                 } break;
  1155.  
  1156.                            case MONSTER_WEST:
  1157.                                 {
  1158.                                 monsters[index].xv = -2 - 2*rand()%2;
  1159.  
  1160.                                 } break;
  1161.  
  1162.                            case MONSTER_NORTH:
  1163.                                 {
  1164.                                 monsters[index].yv = -2 - 2*rand()%2;
  1165.  
  1166.                                 } break;
  1167.  
  1168.  
  1169.                            case MONSTER_SOUTH:
  1170.                                 {
  1171.                                 monsters[index].yv = 2 + 2*rand()%2;
  1172.  
  1173.                                 } break;
  1174.  
  1175.                            default: break;
  1176.  
  1177.                            } // end switch
  1178.  
  1179.                      // set up remaining fields
  1180.  
  1181.                      monsters[index].state        = MONSTER_RANDOM;
  1182.                      monsters[index].direction    = 0;
  1183.                      monsters[index].counter      = 0;
  1184.                      monsters[index].threshold    = 1 + rand()%2;
  1185.                      monsters[index].counter_2    = 0;
  1186.                      monsters[index].threshold_2  = 20 + rand()%20;
  1187.                      monsters[index].object.curr_frame = 8;
  1188.  
  1189.                      } break;
  1190.  
  1191.                 case 4:     // 40% chance of monster chasing player
  1192.                 case 5:
  1193.                 case 6:
  1194.                 case 7:
  1195.                      {
  1196.                      monsters[index].xv           = 0;
  1197.                      monsters[index].yv           = 0;
  1198.  
  1199.                      monsters[index].state        = MONSTER_CHASE;
  1200.                      monsters[index].direction    = 0;
  1201.                      monsters[index].counter      = 0;
  1202.                      monsters[index].threshold    = 1 + rand()%2;
  1203.                      monsters[index].counter_2    = 0;
  1204.                      monsters[index].threshold_2  = 100 + rand()%50;
  1205.                      monsters[index].object.curr_frame = 8;
  1206.  
  1207.                      } break;
  1208.  
  1209.                 case 8: // 20% chance of monster evading player
  1210.                 case 9:
  1211.                      {
  1212.                      monsters[index].xv           = 0;
  1213.                      monsters[index].yv           = 0;
  1214.  
  1215.                      monsters[index].state        = MONSTER_EVADE;
  1216.                      monsters[index].direction    = 0;
  1217.                      monsters[index].counter      = 0;
  1218.                      monsters[index].threshold    = 1 + rand()%2;
  1219.                      monsters[index].counter_2    = 0;
  1220.                      monsters[index].threshold_2  = 20 + rand()%20;
  1221.                      monsters[index].object.curr_frame = 8;
  1222.  
  1223.                      } break;
  1224.  
  1225.                 default:break;
  1226.  
  1227.                 } // end switch
  1228.  
  1229.           } // end if time to change state
  1230.  
  1231.        } // end if not dead
  1232.  
  1233.     } // end for index
  1234.  
  1235. } // end Move_Monsters
  1236.  
  1237. /////////////////////////////////////////////////////////////////////////////
  1238.  
  1239. int Start_Monster(int x, int y)
  1240. {
  1241.  
  1242. // this function is used to start a monster up
  1243.  
  1244. int index;
  1245.  
  1246. // find a monster that isn't being used
  1247.  
  1248. for (index=0; index<NUM_MONSTERS; index++)
  1249.     {
  1250.  
  1251.     // try and find a monster to start
  1252.  
  1253.     if (monsters[index].state == MONSTER_DEAD)
  1254.        {
  1255.  
  1256.        // set up fields
  1257.  
  1258.        monsters[index].x            = x;
  1259.        monsters[index].y            = y;
  1260.        monsters[index].xv           = 0;
  1261.        monsters[index].yv           = 0;
  1262.        monsters[index].state        = MONSTER_STILL;
  1263.        monsters[index].direction    = 0;
  1264.        monsters[index].counter      = 0;
  1265.        monsters[index].threshold    = 1 + rand()%2;
  1266.        monsters[index].counter_2    = 0;
  1267.        monsters[index].threshold_2  = 10 + rand()%10;
  1268.        monsters[index].object.curr_frame = 8;
  1269.  
  1270.        // scan background
  1271.        // extract proper parameters
  1272.  
  1273.        monsters[index].object.x = monsters[index].x;
  1274.        monsters[index].object.y = monsters[index].y;
  1275.  
  1276.        // erase the sprite
  1277.  
  1278.        Behind_Sprite_DB((sprite_ptr)&monsters[index].object);
  1279.  
  1280.        // break out of loop
  1281.  
  1282.        return(1);
  1283.  
  1284.        } // end if dead
  1285.  
  1286.     } // end for index
  1287.  
  1288. return(0);
  1289.  
  1290. } // end Start_Monster
  1291.  
  1292. /////////////////////////////////////////////////////////////////////////////
  1293.  
  1294. void Control_Bat(void)
  1295. {
  1296.  
  1297. // this function controls the bat
  1298.  
  1299. if (bat.state == BAT_DEAD && rand()%250==1)
  1300.    {
  1301.  
  1302.    // play sound
  1303.  
  1304.    Play_Sound(SOUND_BAT);
  1305.  
  1306.    // send the bat out
  1307.  
  1308.    // first select what the bat is going to do
  1309.  
  1310.    switch(rand()%2)
  1311.          {
  1312.  
  1313.          case 0:   // move in a random direction
  1314.               {
  1315.  
  1316.               bat.state = BAT_RANDOM;
  1317.  
  1318.               // select side of screen to start bat from
  1319.  
  1320.               if (rand()%2==1)
  1321.                  {
  1322.                  // start bat from right edge of screen
  1323.  
  1324.                  bat.x  = 224-16;
  1325.                  bat.xv = -4 - rand()%4;
  1326.  
  1327.                  } // end if right side
  1328.               else
  1329.                  {
  1330.                  // start bat from left edge of screen
  1331.  
  1332.                  bat.x  = 0;
  1333.                  bat.xv = 4 + rand()%4;
  1334.  
  1335.                  } // end else left side
  1336.  
  1337.               // set y position and velocity
  1338.  
  1339.               bat.y  = rand()%164;
  1340.               bat.yv = -4 + rand()%8;
  1341.  
  1342.               } break;
  1343.  
  1344.          case 1:   // move in a sinusoidal wave
  1345.               {
  1346.  
  1347.               bat.state = BAT_WAVE;
  1348.  
  1349.               // select side of screen to start bat from
  1350.  
  1351.               if (rand()%2==1)
  1352.                  {
  1353.                  // start bat from right edge of screen
  1354.  
  1355.                  bat.x  = 224-16;
  1356.                  bat.xv = -4 - rand()%4;
  1357.  
  1358.                  } // end if right side
  1359.               else
  1360.                  {
  1361.                  // start bat from left edge of screen
  1362.  
  1363.                  bat.x  = 0;
  1364.                  bat.xv = 4 + rand()%4;
  1365.  
  1366.                  } // end else left side
  1367.  
  1368.               // set y position and velocity
  1369.  
  1370.               bat.y       = 64 + rand()%100;
  1371.               bat.yv      = -1 + rand()%3;
  1372.  
  1373.               // set index into sin look up
  1374.  
  1375.               bat.counter   = 0;
  1376.               bat.threshold = 1 + rand()%3;  // modulate frequency of sin wave
  1377.                                              // that bat follows
  1378.               } break;
  1379.  
  1380.          } // end switch
  1381.  
  1382.    // set current frame
  1383.  
  1384.    bat.object.curr_frame=0;
  1385.  
  1386.    // get background
  1387.  
  1388.    SET_SPRITE_SIZE(16,16);
  1389.    bat.object.x = bat.x;
  1390.    bat.object.y = bat.y;
  1391.  
  1392.    Behind_Sprite_DB((sprite_ptr)&bat.object);
  1393.  
  1394.    } // end if start bat
  1395.  
  1396. } // end Control_Bat
  1397.  
  1398. ///////////////////////////////////////////////////////////////////////////////
  1399.  
  1400. void Move_Bat(void)
  1401. {
  1402.  
  1403. // this moves the bat if it is alive
  1404.  
  1405. if (bat.state != BAT_DEAD)
  1406.    {
  1407.  
  1408.    // first translate
  1409.  
  1410.    bat.x+=bat.xv;
  1411.    bat.y+=bat.yv;
  1412.  
  1413.    // now test state to add on sin modulation
  1414.  
  1415.    if (bat.state==BAT_WAVE)
  1416.       {
  1417.       bat.y+=cos_look[bat.counter];
  1418.  
  1419.       // increment counter
  1420.  
  1421.       if ((bat.counter+=bat.threshold) >= 320)
  1422.            bat.counter=0;
  1423.  
  1424.       } // end if sin state
  1425.  
  1426.    // do animation
  1427.  
  1428.    if (++bat.object.curr_frame >= NUM_BAT_FRAMES)
  1429.       bat.object.curr_frame = 0;
  1430.  
  1431.    // now do boundary detection
  1432.  
  1433.    if ( (bat.x > 224-16) || (bat.x < 0) ||
  1434.         (bat.y > 199-16) || (bat.y < 0) )
  1435.       {
  1436.       // kill bat
  1437.  
  1438.       bat.state = BAT_DEAD;
  1439.  
  1440.       } // end if bat went off screen
  1441.  
  1442.    } // end if alive
  1443.  
  1444. } // end Move_Bat
  1445.  
  1446. //////////////////////////////////////////////////////////////////////////////
  1447.  
  1448. void Erase_Bat(void)
  1449. {
  1450.  
  1451. // this function erases the bat
  1452.  
  1453. if (bat.state != BAT_DEAD)
  1454.    {
  1455.  
  1456.    SET_SPRITE_SIZE(16,16);
  1457.    bat.object.x = bat.x;
  1458.    bat.object.y = bat.y;
  1459.  
  1460.    Erase_Sprite_DB((sprite_ptr)&bat.object);
  1461.  
  1462.    } // end if alive
  1463.  
  1464. } // end Erase_Bat
  1465.  
  1466. //////////////////////////////////////////////////////////////////////////////
  1467.  
  1468. void Behind_Bat(void)
  1469. {
  1470.  
  1471. // this function scans the background under the bat
  1472.  
  1473. if (bat.state != BAT_DEAD)
  1474.    {
  1475.    SET_SPRITE_SIZE(16,16);
  1476.  
  1477.    bat.object.x = bat.x;
  1478.    bat.object.y = bat.y;
  1479.  
  1480.    Behind_Sprite_DB((sprite_ptr)&bat.object);
  1481.  
  1482.    } // end if alive
  1483.  
  1484. } // end Behind_Mother
  1485.  
  1486. //////////////////////////////////////////////////////////////////////////////
  1487.  
  1488. void Draw_Bat(void)
  1489. {
  1490.  
  1491. // this function draws the mothership
  1492.  
  1493. if (bat.state != BAT_DEAD)
  1494.    {
  1495.    SET_SPRITE_SIZE(16,16);
  1496.  
  1497.    bat.object.x = bat.x;
  1498.    bat.object.y = bat.y;
  1499.  
  1500.    Draw_Sprite_DB((sprite_ptr)&bat.object);
  1501.  
  1502.    } // end if alive
  1503.  
  1504. } // end Draw_Bat
  1505.  
  1506. //////////////////////////////////////////////////////////////////////////////
  1507.  
  1508. void Erase_Arrows(void)
  1509. {
  1510.  
  1511. // this function indexes through all the arrows and if they are active
  1512. // erases them by replacing the background color that was under them
  1513.  
  1514. int index;
  1515.  
  1516. // set sprite size for engine
  1517.  
  1518. SET_SPRITE_SIZE(8,8);
  1519.  
  1520. for (index=0; index<NUM_ARROWS; index++)
  1521.     {
  1522.  
  1523.     // is this arrow active
  1524.  
  1525.     if (arrows[index].state == ARROW_ALIVE)
  1526.        {
  1527.  
  1528.        // extract proper parameters
  1529.  
  1530.        arrows[index].object.x = arrows[index].x;
  1531.        arrows[index].object.y = arrows[index].y;
  1532.  
  1533.        // erase the sprite
  1534.  
  1535.        Erase_Sprite_DB((sprite_ptr)&arrows[index].object);
  1536.  
  1537.        } // end if alive
  1538.  
  1539.     } // end for index
  1540.  
  1541. } // end Erase_Arrows
  1542.  
  1543. /////////////////////////////////////////////////////////////////////////////
  1544.  
  1545. void Behind_Arrows(void)
  1546. {
  1547.  
  1548. // this function indexes through all the arrows and if they are active
  1549. // scans the background color that is behind them so it can be replaced later
  1550.  
  1551. int index;
  1552.  
  1553. // set sprite size for engine
  1554.  
  1555. SET_SPRITE_SIZE(8,8);
  1556.  
  1557. for (index=0; index<NUM_ARROWS; index++)
  1558.     {
  1559.  
  1560.     // is this arrow active
  1561.  
  1562.     if (arrows[index].state == ARROW_ALIVE)
  1563.        {
  1564.  
  1565.        // extract proper parameters
  1566.  
  1567.        arrows[index].object.x = arrows[index].x;
  1568.        arrows[index].object.y = arrows[index].y;
  1569.  
  1570.        // scan begind the sprite
  1571.  
  1572.        Behind_Sprite_DB((sprite_ptr)&arrows[index].object);
  1573.  
  1574.        } // end if alive
  1575.  
  1576.     } // end for index
  1577.  
  1578. } // end Behind_Arrows
  1579.  
  1580. /////////////////////////////////////////////////////////////////////////////
  1581.  
  1582. void Draw_Arrows(void)
  1583. {
  1584.  
  1585. // this function indexes through all the arrows and if they are active
  1586. // draws the missile as a bright white pixel on the screen
  1587.  
  1588. int index;
  1589.  
  1590. // set sprite size for engine
  1591.  
  1592. SET_SPRITE_SIZE(8,8);
  1593.  
  1594. for (index=0; index<NUM_ARROWS; index++)
  1595.     {
  1596.  
  1597.     // is this arrow active
  1598.  
  1599.     if (arrows[index].state == ARROW_ALIVE)
  1600.        {
  1601.  
  1602.        // extract proper parameters
  1603.  
  1604.        arrows[index].object.x = arrows[index].x;
  1605.        arrows[index].object.y = arrows[index].y;
  1606.  
  1607.        // draw the sprite
  1608.  
  1609.        Draw_Sprite_DB((sprite_ptr)&arrows[index].object);
  1610.  
  1611.        } // end if alive
  1612.  
  1613.     } // end for index
  1614.  
  1615. } // end Draw_Arrrows
  1616.  
  1617. /////////////////////////////////////////////////////////////////////////////
  1618.  
  1619. void Move_Arrows(void)
  1620. {
  1621.  
  1622. // this function moves the arrows and does all the collision detection
  1623.  
  1624. int index,              // used for loops
  1625.     mindex,             // used to index through monsters
  1626.     arrow_x,            // position of arrow
  1627.     arrow_y,
  1628.     arrow_x_center,     // center of arrow
  1629.     arrow_y_center,
  1630.     cell_x,cell_y,cell_id;  // used to test if arrow has hit a background cell
  1631.  
  1632. // loop thru all arrows and perform a lot of tests
  1633.  
  1634. for (index=0; index<NUM_ARROWS; index++)
  1635.     {
  1636.  
  1637.     // is missile active
  1638.  
  1639.     if (arrows[index].state == ARROW_ALIVE)
  1640.        {
  1641.  
  1642.        // move the arrow
  1643.  
  1644.        arrow_x = (arrows[index].x += arrows[index].xv);
  1645.        arrow_y = (arrows[index].y += arrows[index].yv);
  1646.  
  1647.        // compute center of arrow for ease of computations
  1648.  
  1649.        arrow_x_center = arrow_x+4;
  1650.        arrow_y_center = arrow_y+4;
  1651.  
  1652.        // test if arrow hit an object
  1653.  
  1654.        for (mindex=0; mindex<NUM_MONSTERS; mindex++)
  1655.            {
  1656.  
  1657.            // test arrow against bounding box of monster
  1658.  
  1659.            if (monsters[mindex].state != MONSTER_DEAD &&
  1660.                monsters[mindex].state != MONSTER_DYING &&
  1661.                arrow_x_center > monsters[mindex].x &&
  1662.                arrow_x_center < monsters[mindex].x+16 &&
  1663.                arrow_y_center > monsters[mindex].y &&
  1664.                arrow_y_center < monsters[mindex].y+16)
  1665.               {
  1666.  
  1667.               // kill the monster
  1668.  
  1669.               monsters[mindex].state        = MONSTER_DYING;
  1670.               monsters[mindex].counter_2    = 0;
  1671.               monsters[mindex].threshold_2  = 20;
  1672.  
  1673.               // play the death sound
  1674.  
  1675.               Play_Sound(SOUND_MDIE);
  1676.  
  1677.               // kill the arrow
  1678.  
  1679.               arrows[index].state=ARROW_DEAD;
  1680.  
  1681.               // increase the players score
  1682.  
  1683.               players_score+=250;
  1684.  
  1685.               // break out of this for loop
  1686.  
  1687.               break;
  1688.  
  1689.               } // end if this arrow hit the monster
  1690.  
  1691.            } // end for mindex
  1692.  
  1693.        // test if it's hit the edge of the screen or a wall
  1694.  
  1695.        cell_x = arrow_x_center  >> 4;  // divide by 16 since cells are 16x16 pixels
  1696.        cell_y = arrow_y_center  >> 4;
  1697.  
  1698.        // what is the cell at this location
  1699.  
  1700.        cell_id = world[screen_y][screen_x].cells[cell_y][cell_x];
  1701.  
  1702.        if ( (arrow_x >= 224) || (arrow_x <= 0) ||
  1703.             (arrow_y > (SCREEN_HEIGHT-16)) || (arrow_y <= 0) ||
  1704.             (cell_id < 32))
  1705.             {
  1706.  
  1707.             // kill arrow
  1708.  
  1709.             arrows[index].state = ARROW_DEAD;
  1710.  
  1711.             } // end if off edge of screen
  1712.  
  1713.        } // end if arrow alive
  1714.  
  1715.     } // end for index
  1716.  
  1717. } // end Move_Arrows
  1718.  
  1719. /////////////////////////////////////////////////////////////////////////////
  1720.  
  1721. void Start_Arrow(int x,
  1722.                  int y,
  1723.                  int xv,
  1724.                  int yv,
  1725.                  int direction)
  1726.  
  1727. {
  1728.  
  1729. // this function scans through the arrows array and tries to find one that
  1730. // isn't being used.  this function could be more efficient.
  1731.  
  1732. int index;
  1733.  
  1734. // make sure user has an arrow to fire
  1735.  
  1736. if (num_arrows<=0)
  1737.    return;
  1738.  
  1739. // scan for a useable arrow
  1740.  
  1741. for (index=0; index<NUM_ARROWS; index++)
  1742.     {
  1743.     // is this arrow free?
  1744.  
  1745.     if (arrows[index].state == ARROW_DEAD)
  1746.        {
  1747.  
  1748.        // one less arrow!
  1749.  
  1750.        num_arrows--;
  1751.  
  1752.        // set up fields
  1753.  
  1754.        arrows[index].state = ARROW_ALIVE;
  1755.        arrows[index].x     = x;
  1756.        arrows[index].y     = y;
  1757.        arrows[index].xv    = xv;
  1758.        arrows[index].yv    = yv;
  1759.  
  1760.        // make sure proper animation cell is selected
  1761.  
  1762.        arrows[index].object.curr_frame = direction;
  1763.  
  1764.        // extract proper parameters
  1765.  
  1766.        arrows[index].object.x = x;
  1767.        arrows[index].object.y = y;
  1768.  
  1769.        // set sprite size for engine
  1770.  
  1771.        SET_SPRITE_SIZE(8,8);
  1772.  
  1773.        Behind_Sprite_DB((sprite_ptr)&arrows[index].object);
  1774.  
  1775.        // play sound
  1776.  
  1777.        Play_Sound(SOUND_BOW);
  1778.  
  1779.        break; // exit loop
  1780.  
  1781.        } // end if found a good one
  1782.  
  1783.     } // end for index
  1784.  
  1785. } // end Start_Arrow
  1786.  
  1787. /////////////////////////////////////////////////////////////////////////////
  1788.  
  1789. void Init_Arrows(void)
  1790. {
  1791. // this function just makes sure all the "state" fields of the arrows are
  1792. // dead so that we don't get any strays on start up.  Remember never assume
  1793. // that variables are zeroed on instantiation!
  1794.  
  1795. int index;
  1796.  
  1797. for (index=0; index<NUM_ARROWS; index++)
  1798.     arrows[index].state = ARROW_DEAD;
  1799.  
  1800. } // Init_Arrows
  1801.  
  1802. //////////////////////////////////////////////////////////////////////////////
  1803.  
  1804. void Erase_Fireballs(void)
  1805. {
  1806.  
  1807. // this function indexes through all the fireballs and if they are active
  1808. // erases them by replacing the background color that was under them
  1809.  
  1810. int index;
  1811.  
  1812. // set sprite size for engine
  1813.  
  1814. SET_SPRITE_SIZE(8,8);
  1815.  
  1816. for (index=0; index<NUM_FIREBALLS; index++)
  1817.     {
  1818.  
  1819.     // is this fireball active
  1820.  
  1821.     if (fireballs[index].state == FIREBALL_ALIVE)
  1822.        {
  1823.  
  1824.        // extract proper parameters
  1825.  
  1826.        fireballs[index].object.x = fireballs[index].x;
  1827.        fireballs[index].object.y = fireballs[index].y;
  1828.  
  1829.        // erase the sprite
  1830.  
  1831.        Erase_Sprite_DB((sprite_ptr)&fireballs[index].object);
  1832.  
  1833.        } // end if alive
  1834.  
  1835.     } // end for index
  1836.  
  1837. } // end Erase_Fireballs
  1838.  
  1839. /////////////////////////////////////////////////////////////////////////////
  1840.  
  1841. void Behind_Fireballs(void)
  1842. {
  1843.  
  1844. // this function indexes through all the fireballs and if they are active
  1845. // scans the background color that is behind them so it can be replaced later
  1846.  
  1847. int index;
  1848.  
  1849. // set sprite size for engine
  1850.  
  1851. SET_SPRITE_SIZE(8,8);
  1852.  
  1853. for (index=0; index<NUM_FIREBALLS; index++)
  1854.     {
  1855.  
  1856.     // is this fireball active
  1857.  
  1858.     if (fireballs[index].state == FIREBALL_ALIVE)
  1859.        {
  1860.  
  1861.        // extract proper parameters
  1862.  
  1863.        fireballs[index].object.x = fireballs[index].x;
  1864.        fireballs[index].object.y = fireballs[index].y;
  1865.  
  1866.        // scan begind the sprite
  1867.  
  1868.        Behind_Sprite_DB((sprite_ptr)&fireballs[index].object);
  1869.  
  1870.        } // end if alive
  1871.  
  1872.     } // end for index
  1873.  
  1874. } // end Behind_Fireballs
  1875.  
  1876. /////////////////////////////////////////////////////////////////////////////
  1877.  
  1878. void Draw_Fireballs(void)
  1879. {
  1880.  
  1881. // this function indexes through all the fireballs and if they are active
  1882. // draws the missile as a bright white pixel on the screen
  1883.  
  1884. int index;
  1885.  
  1886. // set sprite size for engine
  1887.  
  1888. SET_SPRITE_SIZE(8,8);
  1889.  
  1890. for (index=0; index<NUM_ARROWS; index++)
  1891.     {
  1892.  
  1893.     // is this arrow active
  1894.  
  1895.     if (fireballs[index].state == FIREBALL_ALIVE)
  1896.        {
  1897.  
  1898.        // extract proper parameters
  1899.  
  1900.        fireballs[index].object.x = fireballs[index].x;
  1901.        fireballs[index].object.y = fireballs[index].y;
  1902.  
  1903.        // draw the sprite
  1904.  
  1905.        Draw_Sprite_DB((sprite_ptr)&fireballs[index].object);
  1906.  
  1907.        } // end if alive
  1908.  
  1909.     } // end for index
  1910.  
  1911. } // end Draw_Fireballs
  1912.  
  1913. /////////////////////////////////////////////////////////////////////////////
  1914.  
  1915. void Move_Fireballs(void)
  1916. {
  1917.  
  1918. // this function moves the fireballs and does all the collision detection
  1919.  
  1920. int index,                 // used for loops
  1921.     fireball_x,            // position of fireball
  1922.     fireball_y,
  1923.     fireball_x_center,     // center of fireball
  1924.     fireball_y_center,
  1925.     cell_x,cell_y,cell_id; // used to test if fireball has hit a background cell
  1926.  
  1927.  
  1928. // loop thru all fireballs and perform a lot of tests
  1929.  
  1930. for (index=0; index<NUM_FIREBALLS; index++)
  1931.     {
  1932.  
  1933.     // is fireball active
  1934.  
  1935.     if (fireballs[index].state == FIREBALL_ALIVE)
  1936.        {
  1937.  
  1938.        // move the fireball
  1939.  
  1940.        fireball_x = (fireballs[index].x += fireballs[index].xv);
  1941.        fireball_y = (fireballs[index].y += fireballs[index].yv);
  1942.  
  1943.        // animate fireball
  1944.  
  1945.        if (++fireballs[index].object.curr_frame == NUM_FIREBALL_FRAMES)
  1946.           fireballs[index].object.curr_frame = 0;
  1947.  
  1948.        // test if fireball hit an object
  1949.  
  1950.        // compute center of fireball for ease of computations
  1951.  
  1952.        fireball_x_center = fireball_x+4;
  1953.        fireball_y_center = fireball_y+4;
  1954.  
  1955.        // test to see if fireball has hit player first
  1956.  
  1957.        if ((fireball_x_center > player.x)    &&
  1958.            (fireball_x_center < player.x+16) &&
  1959.            (fireball_y_center > player.y)    &&
  1960.            (fireball_y_center < player.y+16) )
  1961.           {
  1962.  
  1963.           // hurt player a little
  1964.  
  1965.           if ((health-=10)<0)
  1966.              health=0;
  1967.  
  1968.           // play a hurt sound
  1969.  
  1970.           Play_Sound(SOUND_HURT);
  1971.  
  1972.           // start an explosion
  1973.  
  1974.           Start_Explosion(player.x, player.y,1);
  1975.  
  1976.           // kill fireball
  1977.  
  1978.           fireballs[index].state = FIREBALL_DEAD;
  1979.  
  1980.           // process next interation
  1981.  
  1982.           continue;
  1983.  
  1984.           } // end if player hit
  1985.  
  1986.        // test if it's hit the edge of the screen or a wall
  1987.  
  1988.        cell_x = fireball_x_center  >> 4;  // divide by 16 since cells are 16x16 pixels
  1989.        cell_y = fireball_y_center  >> 4;
  1990.  
  1991.        // what is the cell at this location
  1992.  
  1993.        cell_id = world[screen_y][screen_x].cells[cell_y][cell_x];
  1994.  
  1995.        if ( (fireball_x >= 224) || (fireball_x <= 0) ||
  1996.             (fireball_y > (SCREEN_HEIGHT-16)) || (fireball_y <= 0) ||
  1997.             (cell_id < 32))
  1998.             {
  1999.  
  2000.             // kill fireball
  2001.  
  2002.             fireballs[index].state = FIREBALL_DEAD;
  2003.  
  2004.             // start an explosion
  2005.  
  2006.             Start_Explosion(fireball_x,fireball_y,1+rand()%2);
  2007.  
  2008.             // process next fireball
  2009.  
  2010.             continue;
  2011.  
  2012.             } // end if off edge of screen
  2013.  
  2014.        } // end if fireball alive
  2015.  
  2016.     } // end for index
  2017.  
  2018. } // end Move_Fireballs
  2019.  
  2020. /////////////////////////////////////////////////////////////////////////////
  2021.  
  2022. void Start_Fireball(int x,
  2023.                     int y,
  2024.                     int xv,
  2025.                     int yv)
  2026.  
  2027. {
  2028.  
  2029. // this function scans through the fireballs array and tries to find one that
  2030. // isn't being used.  this function could be more efficient.
  2031.  
  2032. int index;
  2033.  
  2034. // scan for a useable fireball
  2035.  
  2036. for (index=0; index<NUM_FIREBALLS; index++)
  2037.     {
  2038.     // is this fireball free?
  2039.  
  2040.     if (fireballs[index].state == FIREBALL_DEAD)
  2041.        {
  2042.  
  2043.        // set up fields
  2044.  
  2045.        fireballs[index].state = FIREBALL_ALIVE;
  2046.        fireballs[index].x     = x;
  2047.        fireballs[index].y     = y;
  2048.        fireballs[index].xv    = xv;
  2049.        fireballs[index].yv    = yv;
  2050.        fireballs[index].object.curr_frame = 0;
  2051.  
  2052.        // extract proper parameters
  2053.  
  2054.        fireballs[index].object.x = x;
  2055.        fireballs[index].object.y = y;
  2056.  
  2057.        // set sprite size for engine
  2058.  
  2059.        SET_SPRITE_SIZE(8,8);
  2060.  
  2061.        Behind_Sprite_DB((sprite_ptr)&fireballs[index].object);
  2062.  
  2063.        // play sound
  2064.  
  2065.        Play_Sound(SOUND_MFIRE);
  2066.  
  2067.        break; // exit loop
  2068.  
  2069.        } // end if found a good one
  2070.  
  2071.     } // end for index
  2072.  
  2073. } // end Start_Fireball
  2074.  
  2075. /////////////////////////////////////////////////////////////////////////////
  2076.  
  2077. void Init_Fireballs(void)
  2078. {
  2079. // this function just makes sure all the "state" fields of the fireballs are
  2080. // dead so that we don't get any strays on start up.  Remember never assume
  2081. // that variables are zeroed on instantiation!
  2082.  
  2083. int index;
  2084.  
  2085. for (index=0; index<NUM_FIREBALLS; index++)
  2086.     fireballs[index].state = FIREBALL_DEAD;
  2087.  
  2088. } // Init_Fireballs
  2089.  
  2090. ///////////////////////////////////////////////////////////////////////////////
  2091.  
  2092. int Load_Screens(char *filename)
  2093. {
  2094. // this functions opens the screens data file and loads and converts the screen
  2095. // database into the proper format.  The screen database is in the format
  2096. // of 14 rows of 12 characters representing the screen cells then an integer
  2097. // that indicates the number of mosnters on a screen and then a set of coordinate
  2098. // pairs that position each of monsters, then the next screen and so on.
  2099. // the data is standard ASCII text
  2100.  
  2101. // this table is used to convert the ascii characters that represent bitmaps
  2102. // into integers
  2103.  
  2104. static char ascii_to_id[128] =
  2105.  
  2106. //    !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /
  2107.  
  2108.   {0 ,40,0 ,0 ,34,35,0 ,0 ,0 ,0 ,36,37,33,0 ,32,0 ,
  2109.  
  2110. // 0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?
  2111.    0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,39,
  2112.  
  2113. // @  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O
  2114.    0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,
  2115.  
  2116.  
  2117. // P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _
  2118.    15,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,38,0 ,
  2119.  
  2120.  
  2121. // `  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o
  2122.    0 ,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
  2123.  
  2124. // p  q  r  s  t  u  v  w  x  y  z  {  |  }  ~  DEL
  2125.   31 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,99 ,0 ,};
  2126.  
  2127. FILE *fp;                // the file we will read from
  2128.  
  2129. char row[128];           // used to load a row of characters
  2130.  
  2131. int cell_id,             // the final cell id
  2132.     x,y,                 // used for looping
  2133.     index_x,index_y,     // used for looping
  2134.     index,               // used for looping
  2135.     num_monsters,        // number of monsters on current screen
  2136.     monster_x,monster_y; // position of a monster (in pixels/screen coords)
  2137.  
  2138. // try and open screen file
  2139.  
  2140. if (!(fp = fopen(filename,"r")))
  2141.    {
  2142.    printf("\nScreen Loader Error: Can't find file->%s",filename);
  2143.    return(0);
  2144.    } // end if couldn't find file
  2145.  
  2146. printf("\nLoading universe database...");
  2147.  
  2148. // load all sixteen screens, note: they are in the database in row major form
  2149. // i.e. the screens are loaded in this order:
  2150. //
  2151. //  1  2  3  4
  2152. //  5  6  7  8  <---4 X 4
  2153. //  9  10 11 12
  2154. //  13 14 15 16
  2155.  
  2156.  
  2157.  
  2158.  
  2159.  
  2160. for (index_y=0; index_y<WORLD_ROWS; index_y++)
  2161.     {
  2162.  
  2163.     for (index_x=0; index_x<WORLD_COLUMNS; index_x++)
  2164.         {
  2165.  
  2166.         // load the screen
  2167.  
  2168. #if DEBUG
  2169.            printf("\nLoading screen #%d or (%d,%d)\n",index_x+index_y*4,index_x,index_y);
  2170. #endif
  2171.  
  2172.         // reset number of monsters
  2173.  
  2174.         world[index_y][index_x].num_monsters = 0;
  2175.  
  2176.         // reset monster index
  2177.  
  2178.         index=0;
  2179.  
  2180.         for (y=0; y<CELL_ROWS; y++)
  2181.             {
  2182.  
  2183.             // load in next row of ASCII characters
  2184.  
  2185.             fscanf(fp,"%s",row);
  2186.  
  2187. #if DEBUG
  2188.             printf("\n%s\n",row);
  2189. #endif
  2190.  
  2191.             // process row
  2192.  
  2193.             for (x=0; x<CELL_COLUMNS; x++)
  2194.                 {
  2195.  
  2196.                 // convert id using ascii to id look up table
  2197.  
  2198.                 cell_id = ascii_to_id[row[x]-32];
  2199.  
  2200. #if DEBUG
  2201.                 printf("%d,",cell_id);
  2202. #endif
  2203.  
  2204.                 // place id into data structure at proper location
  2205.  
  2206.                 if (cell_id < 99)
  2207.                     world[index_y][index_x].cells[y][x] = cell_id;
  2208.                 else
  2209.                    {
  2210.                    // this must be a monster so install it into database
  2211.  
  2212.                    // scale monster position
  2213.  
  2214.                    monster_x = x << 4;  // * 16
  2215.                    monster_y = y << 4;  // * 16
  2216.  
  2217. #if DEBUG
  2218.                    printf("\n monster at (%d,%d)",monster_x,monster_y);
  2219. #endif
  2220.                    // record data in database
  2221.  
  2222.                    world[index_y][index_x].positions[index].x = monster_x;
  2223.                    world[index_y][index_x].positions[index].y = monster_y;
  2224.  
  2225.                    index++;
  2226.  
  2227.                    // place a neutral tile at this location
  2228.  
  2229.                    world[index_y][index_x].cells[y][x] = 32;
  2230.  
  2231.                    // record number of monsters in database
  2232.  
  2233.                    world[index_y][index_x].num_monsters++;
  2234.  
  2235.                    } // end else
  2236.  
  2237.                 } // end for x
  2238.  
  2239.             } // end for y
  2240.  
  2241.         } // end for index_x
  2242.  
  2243.     } // end for index_y
  2244.  
  2245. } // end Load_Screens
  2246.  
  2247. ///////////////////////////////////////////////////////////////////////////////
  2248.  
  2249. void Draw_Screen(int wx,int wy)
  2250. {
  2251. // this function uses the sent coords to select one of the screens from the
  2252. // world database to draw into the double buffer. note: everything that
  2253. // is currently in the double bufer will be obliterated after this call to
  2254. // reflect the new matrix ...Wrath of Khan
  2255.  
  2256. screen_ptr current_screen;   // pointer to current screen
  2257.  
  2258. int cell_id,                 // the cell id
  2259.     index_x,index_y;         // looping variables
  2260.  
  2261. // set sprite size
  2262.  
  2263. SET_SPRITE_SIZE(16,16);
  2264.  
  2265. // obtain a pointer to the current screen
  2266.  
  2267. current_screen = &world[wy][wx];
  2268.  
  2269. for (index_y=0; index_y<CELL_ROWS; index_y++)
  2270.     {
  2271.  
  2272.     for (index_x=0; index_x<CELL_COLUMNS; index_x++)
  2273.         {
  2274.  
  2275.         // extract the cell id
  2276.  
  2277.         cell_id = current_screen->cells[index_y][index_x];
  2278.  
  2279.         // blit it into double buffer
  2280.  
  2281.         // test for texture type
  2282.  
  2283.         if (cell_id < 16)
  2284.            {
  2285.            // use the sprite that holds the blue walls
  2286.  
  2287.            // set up sprite frame and position
  2288.  
  2289.            wall_1.curr_frame = cell_id;
  2290.  
  2291.            // compute screen coordinates of bitmap cell
  2292.  
  2293.            wall_1.x          = index_x << 4;  // * 16
  2294.            wall_1.y          = index_y << 4;  // * 16
  2295.  
  2296.            Draw_Sprite_DB((sprite_ptr)&wall_1);
  2297.  
  2298.            } // end if 0-15 blue walls
  2299.         else
  2300.         if (cell_id < 32)
  2301.            {
  2302.            // use the sprite that holds the green walls
  2303.  
  2304.            // set up sprite frame and position
  2305.  
  2306.            wall_2.curr_frame = cell_id-16;
  2307.  
  2308.            // compute screen coordinates of bitmap cell
  2309.  
  2310.            wall_2.x          = index_x << 4;  // * 16
  2311.            wall_2.y          = index_y << 4;  // * 16
  2312.  
  2313.            Draw_Sprite_DB((sprite_ptr)&wall_2);
  2314.  
  2315.            } // end if 16-31 green walls
  2316.         else
  2317.            {
  2318.            // must be floor texture
  2319.  
  2320.            // set up sprite frame and position
  2321.  
  2322.            floors.curr_frame = cell_id-32;
  2323.  
  2324.            // compute screen coordinates of bitmap cell
  2325.  
  2326.            floors.x          = index_x << 4;  // * 16
  2327.            floors.y          = index_y << 4;  // * 16
  2328.  
  2329.            Draw_Sprite_DB((sprite_ptr)&floors);
  2330.  
  2331.            } // end else must be floor
  2332.  
  2333.         } // end for x
  2334.  
  2335.     } // end for y
  2336.  
  2337. } // end Draw_Screen
  2338.  
  2339. ///////////////////////////////////////////////////////////////////////////////
  2340.  
  2341. void Init_Monsters(void)
  2342. {
  2343. // this function sets the state of all monsters to dead
  2344.  
  2345. int index;
  2346.  
  2347. for (index=0; index<NUM_MONSTERS; index++)
  2348.     monsters[index].state = MONSTER_DEAD;
  2349.  
  2350. } // end Init_Monsters
  2351.  
  2352. //////////////////////////////////////////////////////////////////////////////
  2353.  
  2354. void Start_Monsters(int wx,int wy)
  2355. {
  2356.  
  2357. // this function refers to the world database and uses the monster info.
  2358. // to start up monsters for the screen
  2359.  
  2360. int index,
  2361.     num_monsters;
  2362.  
  2363. // first kill all the monsters
  2364.  
  2365. Init_Monsters();
  2366.  
  2367. // extract number of monsters from database
  2368.  
  2369. num_monsters = world[wy][wx].num_monsters;
  2370.  
  2371. // start the monsters up
  2372.  
  2373. for (index=0;index<num_monsters; index++)
  2374.     {
  2375.  
  2376.     Start_Monster(world[wy][wx].positions[index].x,
  2377.                   world[wy][wx].positions[index].y);
  2378.  
  2379.     } // end for index
  2380.  
  2381. } // end Start_Monsters
  2382.  
  2383. ///////////////////////////////////////////////////////////////////////////////
  2384.  
  2385. void Save_Monsters(int wx,int wy)
  2386. {
  2387. // this function is used to save the position information about each monster
  2388. // back into the world database before a screen warp occurs
  2389.  
  2390. int index;            // loop variable
  2391.  
  2392. // reset counter
  2393.  
  2394. world[wy][wx].num_monsters = 0;
  2395.  
  2396. // try and find active monsters and then store their positions back into
  2397. // the world database so when the player comes back to the room it seems
  2398. // like the monsters didn't start from their original positions
  2399.  
  2400. for (index=0; index<NUM_MONSTERS; index++)
  2401.     {
  2402.     // is this a live one
  2403.  
  2404.     if (monsters[index].state!=MONSTER_DEAD)
  2405.        {
  2406.  
  2407.        // insert into data base
  2408.  
  2409.        world[wy][wx].positions[index].x = monsters[index].x;
  2410.        world[wy][wx].positions[index].y = monsters[index].y;
  2411.  
  2412.        // increment number of monsters
  2413.  
  2414.        world[wy][wx].num_monsters++;
  2415.  
  2416.        } // end if not dead
  2417.  
  2418.     } // end for index
  2419.  
  2420. // at this point the database has been updated and a screen warp can be made
  2421. // to another screen and then back with continuity
  2422.  
  2423. } // end Save_Monsters
  2424.  
  2425. ///////////////////////////////////////////////////////////////////////////////
  2426.  
  2427. int Initialize_Sound_System(void)
  2428. {
  2429.  
  2430. // this function loads in the ct-voice.drv driver and the configuration file
  2431. // and sets up the sound driver appropriately
  2432.  
  2433. FILE *fp;
  2434.  
  2435. // test if driver is on disk
  2436.  
  2437. if ( (fp=fopen("ct-voice.drv","rb"))==NULL)
  2438.    {
  2439.    return(0);
  2440.    } // end if not file
  2441.  
  2442. fclose(fp);
  2443.  
  2444. // load up sound configuration file
  2445.  
  2446. if ( (fp=fopen("venture.cfg","r"))==NULL )
  2447.    {
  2448.    printf("\nSound configuration file not found...");
  2449.    printf("\nUsing default values of port 220h and interrupt 5.");
  2450.  
  2451.    } // end if open sound configuration file
  2452. else
  2453.    {
  2454.  
  2455.    fscanf(fp,"%d %d",&sound_port, &sound_int);
  2456.    printf("\nSetting sound system to port %d decimal with interrupt %d.",
  2457.                                                     sound_port, sound_int);
  2458.  
  2459.    } // end else
  2460.  
  2461. // start up the whole sound system and load everything
  2462.  
  2463. Voc_Load_Driver();
  2464.  
  2465. Voc_Set_Port(sound_port);
  2466. Voc_Set_IRQ(sound_int);
  2467. Voc_Init_Driver();
  2468. Voc_Get_Version();
  2469. Voc_Set_Status_Addr((char far *)&ct_voice_status);
  2470.  
  2471. // load in sounds
  2472.  
  2473. sound_fx[SOUND_HURT   ]  = Voc_Load_Sound("VHURT.VOC   ",&sound_lengths[SOUND_HURT    ]);
  2474. sound_fx[SOUND_HEALTH ]  = Voc_Load_Sound("VHEALTH.VOC ",&sound_lengths[SOUND_HEALTH  ]);
  2475. sound_fx[SOUND_MDIE   ]  = Voc_Load_Sound("VMDIE.VOC   ",&sound_lengths[SOUND_MDIE    ]);
  2476. sound_fx[SOUND_MFIRE  ]  = Voc_Load_Sound("VMFIRE.VOC  ",&sound_lengths[SOUND_MFIRE   ]);
  2477. sound_fx[SOUND_MONEY  ]  = Voc_Load_Sound("VMONEY.VOC  ",&sound_lengths[SOUND_MONEY   ]);
  2478. sound_fx[SOUND_EAT    ]  = Voc_Load_Sound("VEAT.VOC    ",&sound_lengths[SOUND_EAT     ]);
  2479. sound_fx[SOUND_FARROW ]  = Voc_Load_Sound("VFARROW.VOC ",&sound_lengths[SOUND_FARROW  ]);
  2480. sound_fx[SOUND_POTION ]  = Voc_Load_Sound("VPOTION.VOC ",&sound_lengths[SOUND_POTION  ]);
  2481. sound_fx[SOUND_ARROW  ]  = Voc_Load_Sound("VARROW.VOC  ",&sound_lengths[SOUND_ARROW   ]);
  2482. sound_fx[SOUND_BOW    ]  = Voc_Load_Sound("VBOW.VOC    ",&sound_lengths[SOUND_BOW     ]);
  2483. sound_fx[SOUND_BAT    ]  = Voc_Load_Sound("VBAT.VOC    ",&sound_lengths[SOUND_BAT     ]);
  2484. sound_fx[SOUND_INTRO  ]  = Voc_Load_Sound("VINTRO.VOC  ",&sound_lengths[SOUND_INTRO   ]);
  2485. sound_fx[SOUND_DAGGER ]  = Voc_Load_Sound("VDAGGER.VOC ",&sound_lengths[SOUND_DAGGER  ]);
  2486. sound_fx[SOUND_END    ]  = Voc_Load_Sound("VEND.VOC    ",&sound_lengths[SOUND_END     ]);
  2487. sound_fx[SOUND_DEATH  ]  = Voc_Load_Sound("VDEATH.VOC  ",&sound_lengths[SOUND_DEATH   ]);
  2488. sound_fx[SOUND_GOAL   ]  = Voc_Load_Sound("VGOAL.VOC   ",&sound_lengths[SOUND_GOAL    ]);
  2489.  
  2490. // turn on speaker
  2491.  
  2492. Voc_Set_Speaker(1);
  2493.  
  2494. // success
  2495.  
  2496. return(1);
  2497.  
  2498. } // end Initialize_Sound_System
  2499.  
  2500. /////////////////////////////////////////////////////////////////////////////
  2501.  
  2502. void Close_Sound_System(void)
  2503. {
  2504.  
  2505. // this function closes down the sound system
  2506.  
  2507. // make sure there is sound
  2508.  
  2509. if (sound_available)
  2510.    {
  2511.    // turn off speaker
  2512.  
  2513.    Voc_Set_Speaker(0);
  2514.  
  2515.    // unload sounds
  2516.  
  2517.    Voc_Unload_Sound(sound_fx[ SOUND_HURT   ]);
  2518.    Voc_Unload_Sound(sound_fx[ SOUND_HEALTH ]);
  2519.    Voc_Unload_Sound(sound_fx[ SOUND_MDIE   ]);
  2520.    Voc_Unload_Sound(sound_fx[ SOUND_MFIRE  ]);
  2521.    Voc_Unload_Sound(sound_fx[ SOUND_MONEY  ]);
  2522.    Voc_Unload_Sound(sound_fx[ SOUND_EAT    ]);
  2523.    Voc_Unload_Sound(sound_fx[ SOUND_FARROW ]);
  2524.    Voc_Unload_Sound(sound_fx[ SOUND_POTION ]);
  2525.    Voc_Unload_Sound(sound_fx[ SOUND_ARROW  ]);
  2526.    Voc_Unload_Sound(sound_fx[ SOUND_BOW    ]);
  2527.    Voc_Unload_Sound(sound_fx[ SOUND_BAT    ]);
  2528.    Voc_Unload_Sound(sound_fx[ SOUND_DAGGER ]);
  2529.    Voc_Unload_Sound(sound_fx[ SOUND_INTRO  ]);
  2530.    Voc_Unload_Sound(sound_fx[ SOUND_END    ]);
  2531.    Voc_Unload_Sound(sound_fx[ SOUND_DEATH  ]);
  2532.    Voc_Unload_Sound(sound_fx[ SOUND_GOAL   ]);
  2533.  
  2534.    Voc_Terminate_Driver();
  2535.  
  2536.    } // end if sound
  2537.  
  2538. } // end Close_Sound_System
  2539.  
  2540. /////////////////////////////////////////////////////////////////////////////
  2541.  
  2542. void Play_Sound(int sound)
  2543. {
  2544. // this function plays a sound by turning off one if there is a sound playing
  2545. // and then playing the sent sound
  2546.  
  2547. // make sure there is a sound system first
  2548.  
  2549. if (sound_available && start_death!=1)
  2550.    {
  2551.  
  2552.    // stop the current sound (if there is one)
  2553.  
  2554.    Voc_Stop_Sound();
  2555.  
  2556.    // play sent sound
  2557.  
  2558.    Voc_Play_Sound(sound_fx[sound] , sound_lengths[sound]);
  2559.  
  2560.    } // end if sound available
  2561.  
  2562. } // end Play_Sound
  2563.  
  2564. ///////////////////////////////////////////////////////////////////////////////
  2565.  
  2566. unsigned char Get_Pixel_DB(int x,int y)
  2567. {
  2568.  
  2569. // gets the color value of pixel at (x,y) from the double buffer
  2570.  
  2571. return double_buffer[((y<<8) + (y<<6)) + x];
  2572.  
  2573. } // end Get_Pixel_DB
  2574.  
  2575. //////////////////////////////////////////////////////////////////////////////
  2576.  
  2577. void Do_Intro(void)
  2578. {
  2579. // this function displays the introduction screen and then melts it
  2580.  
  2581. // load intro screen and display for a few secs.
  2582.  
  2583. PCX_Init((pcx_picture_ptr)&intro_pcx);
  2584.  
  2585. PCX_Load("ventint.pcx", (pcx_picture_ptr)&intro_pcx,1);
  2586.  
  2587. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  2588.  
  2589. // play a sound
  2590.  
  2591. Play_Sound(SOUND_INTRO );
  2592.  
  2593. // let user see it
  2594.  
  2595. Delay(50);
  2596.  
  2597. Fade_Lights();
  2598.  
  2599. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  2600.  
  2601. } // end Do_Intro
  2602.  
  2603. ///////////////////////////////////////////////////////////////////////////////
  2604.  
  2605. void Load_Environment(void)
  2606. {
  2607. // this function loads the imagery for the environment
  2608.  
  2609. int index,  // loop variables
  2610.     index_2;
  2611.  
  2612. // load in imagery
  2613.  
  2614. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  2615.  
  2616. PCX_Load("ventimg.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  2617.  
  2618. // initialize the wall sprites and floor sprites
  2619.  
  2620. SET_SPRITE_SIZE(16,16);
  2621.  
  2622. Sprite_Init((sprite_ptr)&wall_1,0,0,0,0,0,0);
  2623. Sprite_Init((sprite_ptr)&wall_2,0,0,0,0,0,0);
  2624. Sprite_Init((sprite_ptr)&floors,0,0,0,0,0,0);
  2625.  
  2626. // load in frames for walls
  2627.  
  2628. for (index=0; index<16; index++)
  2629.     {
  2630.  
  2631.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2632.                     (sprite_ptr)&wall_1,index,index,0);
  2633.  
  2634.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2635.                     (sprite_ptr)&wall_2,index,index,1);
  2636.  
  2637.     } // end for
  2638.  
  2639. // now load the floor textures
  2640.  
  2641. for (index=0; index<9; index++)
  2642.     {
  2643.  
  2644.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2645.                     (sprite_ptr)&floors,index,index,2);
  2646.     } // end for
  2647.  
  2648. // now load the player
  2649.  
  2650. Sprite_Init((sprite_ptr)&player,0,0,0,0,0,0);
  2651.  
  2652. // load in frames for player
  2653.  
  2654. for (index=0; index<16; index++)
  2655.     {
  2656.  
  2657.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2658.                     (sprite_ptr)&player,index,index,3);
  2659.  
  2660.     } // end for
  2661.  
  2662. // death sequence
  2663.  
  2664. for (index=16; index<21; index++)
  2665.     {
  2666.  
  2667.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2668.                     (sprite_ptr)&player,index,index-16,6);
  2669.  
  2670.     } // end for
  2671.  
  2672.  
  2673. // set up state information
  2674.  
  2675. player.x             = 112-16;
  2676. player.y             = 120;
  2677. player.state         = PLAYER_ALIVE;
  2678. player.motion_speed  = 1;
  2679. player.motion_clock  = 0;
  2680.  
  2681. player.curr_frame = 9;
  2682.  
  2683. // load in the monsters
  2684.  
  2685. for (index=0; index<NUM_MONSTERS; index++)
  2686.     {
  2687.  
  2688.     Sprite_Init((sprite_ptr)&monsters[index].object,0,0,0,0,0,0);
  2689.  
  2690.  
  2691.     for (index_2=0; index_2<NUM_MONSTER_FRAMES; index_2++)
  2692.          PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2693.                         (sprite_ptr)&monsters[index].object,index_2,index_2,4);
  2694.  
  2695.  
  2696.     // set up state information
  2697.  
  2698.     monsters[index].x                 = 0;
  2699.     monsters[index].y                 = 0;
  2700.     monsters[index].state             = MONSTER_DEAD;
  2701.     monsters[index].object.curr_frame = 8;
  2702.  
  2703.     } // end for
  2704.  
  2705. // now load the bat
  2706.  
  2707. Sprite_Init((sprite_ptr)&bat.object,0,0,0,0,0,0);
  2708.  
  2709. // load in frames for bat
  2710.  
  2711. for (index=0; index<NUM_BAT_FRAMES; index++)
  2712.     {
  2713.  
  2714.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2715.                     (sprite_ptr)&bat.object,index,index,5);
  2716.  
  2717.     } // end for
  2718.  
  2719. // set up state information
  2720.  
  2721. bat.x                 = 0;
  2722. bat.y                 = 0;
  2723. bat.state             = BAT_DEAD;
  2724.  
  2725. bat.object.curr_frame = 0;
  2726.  
  2727. // delete the pcx file
  2728.  
  2729. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  2730.  
  2731. } // end Load_Environment
  2732.  
  2733. ////////////////////////////////////////////////////////////////////////////
  2734.  
  2735. void Load_Weapons(void)
  2736. {
  2737.  
  2738. int index;
  2739.  
  2740. // load in imagery for missiles
  2741.  
  2742. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  2743.  
  2744. PCX_Load("ventweap.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  2745.  
  2746. // initialize arrows and extract bitmaps
  2747.  
  2748. SET_SPRITE_SIZE(8,8);
  2749.  
  2750. // initialize the sprite for each arrow
  2751.  
  2752. for (index=0; index<NUM_ARROWS; index++)
  2753.     {
  2754.  
  2755.     Sprite_Init((sprite_ptr)&arrows[index].object,0,0,0,0,0,0);
  2756.  
  2757.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2758.                     (sprite_ptr)&arrows[index].object,0,0,0);
  2759.  
  2760.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2761.                     (sprite_ptr)&arrows[index].object,1,1,0);
  2762.  
  2763.  
  2764.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2765.                     (sprite_ptr)&arrows[index].object,2,2,0);
  2766.  
  2767.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2768.                     (sprite_ptr)&arrows[index].object,3,3,0);
  2769.  
  2770.     // set some important fields
  2771.  
  2772.     arrows[index].x                 = 0;
  2773.     arrows[index].y                 = 0;
  2774.     arrows[index].object.curr_frame = 0;
  2775.     arrows[index].state             = ARROW_DEAD;
  2776.  
  2777.     } // end for
  2778.  
  2779. // initialize the sprite for each fireball
  2780.  
  2781. for (index=0; index<NUM_FIREBALLS; index++)
  2782.     {
  2783.  
  2784.     Sprite_Init((sprite_ptr)&fireballs[index].object,0,0,0,0,0,0);
  2785.  
  2786.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2787.                     (sprite_ptr)&fireballs[index].object,0,0,1);
  2788.  
  2789.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2790.                     (sprite_ptr)&fireballs[index].object,1,1,1);
  2791.  
  2792.  
  2793.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2794.                     (sprite_ptr)&fireballs[index].object,2,2,1);
  2795.  
  2796.     // set some important fields
  2797.  
  2798.     fireballs[index].x                 = 0;
  2799.     fireballs[index].y                 = 0;
  2800.     fireballs[index].object.curr_frame = 0;
  2801.     fireballs[index].state             = FIREBALL_DEAD;
  2802.  
  2803.     } // end for
  2804.  
  2805. // delete the pcx file
  2806.  
  2807. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  2808.  
  2809.  
  2810. // load in imagery for explosions
  2811.  
  2812. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  2813.  
  2814. PCX_Load("ventexpl.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  2815.  
  2816. // initialize the explosions and extract bitmaps
  2817.  
  2818. SET_SPRITE_SIZE(16,16);
  2819.  
  2820. // load in frames for explosions
  2821.  
  2822. for (index=0; index<NUM_EXPLOSIONS; index++)
  2823.     {
  2824.  
  2825.     Sprite_Init((sprite_ptr)&explosions[index],0,0,0,0,0,0);
  2826.  
  2827.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2828.                     (sprite_ptr)&explosions[index],0,0,0);
  2829.  
  2830.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2831.                     (sprite_ptr)&explosions[index],1,1,0);
  2832.  
  2833.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2834.                     (sprite_ptr)&explosions[index],2,2,0);
  2835.  
  2836.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  2837.                     (sprite_ptr)&explosions[index],3,3,0);
  2838.  
  2839.     } // end for
  2840.  
  2841. // delete the pcx file
  2842.  
  2843. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  2844.  
  2845. } // end Load_Weapons
  2846.  
  2847. ////////////////////////////////////////////////////////////////////////////
  2848.  
  2849. void Load_Background(void)
  2850. {
  2851.  
  2852. // load in the background image into the double buffer
  2853.  
  2854. PCX_Init((pcx_picture_ptr)&background_pcx);
  2855.  
  2856. PCX_Load("ventbak.pcx", (pcx_picture_ptr)&background_pcx,1);
  2857.  
  2858. // copy the background into the double buffer
  2859.  
  2860. _fmemcpy((char far *)double_buffer,
  2861.          (char far *)(background_pcx.buffer),
  2862.          SCREEN_WIDTH*SCREEN_HEIGHT);
  2863.  
  2864. PCX_Delete((pcx_picture_ptr)&background_pcx);
  2865.  
  2866. } // Load_Background
  2867.  
  2868. ///////////////////////////////////////////////////////////////////////////////
  2869.  
  2870. void Draw_Stats(void)
  2871. {
  2872.  
  2873. // this function draws the players statistics in the display module
  2874.  
  2875. char buffer[128];
  2876.  
  2877. // show the score
  2878.  
  2879. sprintf(buffer,"%ld",players_score);
  2880.  
  2881. Blit_String_DB(268+2,53,9,buffer,0);
  2882.  
  2883. // show the health
  2884.  
  2885. sprintf(buffer,"%d%% ",health);
  2886.  
  2887. // draw health in red if weak
  2888.  
  2889. if (health>=20)
  2890.     {
  2891.     Blit_String_DB(270+2,78,10,buffer,0);
  2892.  
  2893.     // set counter almost at threshold
  2894.     weak_counter=350;
  2895.     }
  2896. else
  2897.     {
  2898.     Blit_String_DB(270+2,78,12,buffer,0);
  2899.  
  2900.     // test if we have verbally told player he is weak
  2901.  
  2902.     if (++weak_counter>400)
  2903.        {
  2904.  
  2905.        Play_Sound(SOUND_HEALTH);
  2906.  
  2907.        // reset counter
  2908.  
  2909.        weak_counter=0;
  2910.  
  2911.        } // end if speak
  2912.  
  2913.     } // end else player weak
  2914.  
  2915. // show the arrows
  2916.  
  2917. sprintf(buffer,"%d ",num_arrows);
  2918.  
  2919. Blit_String_DB(275+2,103,6,buffer,0);
  2920.  
  2921. // show the gold
  2922.  
  2923. sprintf(buffer,"%d",gold_pieces);
  2924.  
  2925. Blit_String_DB(259+2,127,14,buffer,0);
  2926.  
  2927. // show the silver
  2928.  
  2929. sprintf(buffer,"%d",silver_pieces);
  2930.  
  2931. Blit_String_DB(268+2,152,7,buffer,0);
  2932.  
  2933. } // end Draw_Stats
  2934.  
  2935. ///////////////////////////////////////////////////////////////////////////////
  2936.  
  2937. void Glow_Dagger(void)
  2938. {
  2939. // this is a self contained functions that makes the dagger glow
  2940.  
  2941. static int clock=0,       // used for timing, note: they are static!
  2942.            entered_yet=0,
  2943.            ci=2;          // used to make color increase or decrease
  2944.  
  2945. RGB_color color;          // used to hold color values during processing
  2946.  
  2947. // test if function is being called for first time
  2948.  
  2949. if (!entered_yet)
  2950.    {
  2951.  
  2952.    // reset the palette registers to bright blue, dark blue, dark blue
  2953.  
  2954.    color.red   = 32;
  2955.    color.green = 0;
  2956.    color.blue  = 0;
  2957.  
  2958.    Set_Palette_Register(254,(RGB_color_ptr)&color);
  2959.  
  2960.    // system has initialized, so flag it
  2961.  
  2962.    entered_yet=1;
  2963.  
  2964.    } // end if first time into function
  2965.  
  2966. // try and glow dagger
  2967.  
  2968.    if (++clock==1)  // is it time to rotate
  2969.       {
  2970.       // get the color
  2971.  
  2972.       Get_Palette_Register(254,(RGB_color_ptr)&color);
  2973.  
  2974.       // increase or decrease color
  2975.  
  2976.       color.red+=ci;
  2977.  
  2978.       // test if max or min or range has been hit
  2979.  
  2980.       if (color.red>63 || color.red<2)
  2981.          ci=-ci;
  2982.  
  2983.       // set the colors
  2984.  
  2985.       Set_Palette_Register(254,(RGB_color_ptr)&color);
  2986.  
  2987.       // reset the clock
  2988.  
  2989.       clock=0;
  2990.  
  2991.       } // end if time to rotate
  2992.  
  2993. } // end Glow_Dagger
  2994.  
  2995. //////////////////////////////////////////////////////////////////////////////
  2996.  
  2997. void Show_Instructions(void)
  2998. {
  2999. // this function displays the instructions and then disolves them
  3000.  
  3001. // load instruction screen and display it until a key press
  3002.  
  3003. PCX_Init((pcx_picture_ptr)&intro_pcx);
  3004.  
  3005. PCX_Load("ventins.pcx", (pcx_picture_ptr)&intro_pcx,1);
  3006.  
  3007. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  3008.  
  3009. // let user see it
  3010.  
  3011. while(!kbhit()){};
  3012.  
  3013. getch();
  3014.  
  3015. // let's try this screen transition
  3016.  
  3017. Sheer();
  3018.  
  3019. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  3020.  
  3021. } // end Show_Instructions
  3022.  
  3023. ////////////////////////////////////////////////////////////////////////////////
  3024.  
  3025. void Do_Goal(void)
  3026. {
  3027. // this function displays the goal screen and then disolves it
  3028.  
  3029. // load instruction screen and display it until a key press
  3030.  
  3031. PCX_Init((pcx_picture_ptr)&intro_pcx);
  3032.  
  3033. PCX_Load("ventgoal.pcx", (pcx_picture_ptr)&intro_pcx,1);
  3034.  
  3035. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  3036.  
  3037. while(kbhit())
  3038.       getch();
  3039.  
  3040. // let user see it
  3041.  
  3042. while(!kbhit()){};
  3043.  
  3044. getch();
  3045.  
  3046. // let's try this screen transition
  3047.  
  3048. Disolve();
  3049.  
  3050. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  3051.  
  3052. } // end Do_Goal
  3053.  
  3054. // M A I N /////////////////////////////////////////////////////////////////
  3055.  
  3056. void main(void)
  3057. {
  3058.  
  3059. int done=0,         // main event loop exit flag
  3060.     index,          // loop variable
  3061.     cell_x,cell_y,  // cell location
  3062.     dx,dy,          // general deltas
  3063.     cell_id;        // bitmap id of a cell
  3064.  
  3065. char buffer[128]; // used for string printing
  3066.  
  3067. // begin the program
  3068.  
  3069. printf("\nStarting Venture...");
  3070.  
  3071. Load_Screens("venture.dat");
  3072.  
  3073. // initialize sound system
  3074.  
  3075. sound_available = Initialize_Sound_System();
  3076.  
  3077. // let user think the computer is working hard
  3078.  
  3079. Delay(50);
  3080.  
  3081. // set video mode to 320x200 256 color mode
  3082.  
  3083. Set_Video_Mode(VGA256);
  3084.  
  3085. // create a double buffer
  3086.  
  3087. if (!Create_Double_Buffer(SCREEN_HEIGHT))
  3088.    {
  3089.  
  3090.    printf("\nNot enough memory to create double buffer.");
  3091.  
  3092.    } // end if
  3093.  
  3094. // clear the double buffer
  3095.  
  3096. Fill_Double_Buffer(0);
  3097.  
  3098. // impress user (at least try to)
  3099.  
  3100. Do_Intro();
  3101.  
  3102. // show the instructions
  3103.  
  3104. Show_Instructions();
  3105.  
  3106. // load imagery for game
  3107.  
  3108. Load_Environment();
  3109.  
  3110. // load the background into double buffer
  3111.  
  3112. Load_Background();
  3113.  
  3114. // load in imagery for weapons
  3115.  
  3116. Load_Weapons();
  3117.  
  3118. // initialize everything
  3119.  
  3120. Init_Arrows();
  3121.  
  3122. Init_Fireballs();
  3123.  
  3124. Init_Explosions();
  3125.  
  3126. // create all look up tables
  3127.  
  3128. Create_Lookups();
  3129.  
  3130. // place player in top left corner of universe
  3131. // x...
  3132. // ....
  3133. // ....
  3134. // ....
  3135.  
  3136. screen_x = 0;
  3137. screen_y = 0;
  3138.  
  3139. // install the new keyboard driver
  3140.  
  3141. Install_Keyboard();
  3142.  
  3143.  
  3144.  
  3145. // draw the initial view
  3146.  
  3147. Draw_Screen(screen_x, screen_y);
  3148.  
  3149. // the the monsters
  3150.  
  3151. Start_Monsters(screen_x, screen_y);
  3152.  
  3153. // scan under player
  3154.  
  3155. SET_SPRITE_SIZE(16,16);
  3156. Behind_Sprite_DB((sprite_ptr)&player);
  3157.  
  3158. // begin main event loop
  3159.  
  3160. while(!done)
  3161.      {
  3162.      // erase everything
  3163.  
  3164.      SET_SPRITE_SIZE(16,16);
  3165.  
  3166.      Erase_Sprite_DB((sprite_ptr)&player);
  3167.  
  3168.      Erase_Arrows();
  3169.  
  3170.      Erase_Fireballs();
  3171.  
  3172.      Erase_Explosions();
  3173.  
  3174.      Erase_Bat();
  3175.  
  3176.      Erase_Monsters();
  3177.  
  3178.      // reset screen change flag
  3179.  
  3180.      screen_change=0;
  3181.  
  3182.      dx=dy=0;
  3183.  
  3184.      // test if user has pressed a key
  3185.  
  3186.      if ((key_table[INDEX_RIGHT] || key_table[INDEX_LEFT] ||
  3187.           key_table[INDEX_UP]    || key_table[INDEX_DOWN] ||
  3188.           key_table[INDEX_SPACE] || key_table[INDEX_ESC] ) &&
  3189.           (player.state==PLAYER_ALIVE))
  3190.         {
  3191.  
  3192.         // what key was pressed
  3193.  
  3194.  
  3195.               if (key_table[INDEX_ESC]) // exit game
  3196.                  {
  3197.                    done=2;
  3198.  
  3199.                  } // end if esc
  3200.               else
  3201.               if (key_table[INDEX_LEFT]) // move left
  3202.                  {
  3203.                  // only process if enough cycles have passed
  3204.  
  3205.                  if (++player.motion_clock==player.motion_speed)
  3206.                     {
  3207.  
  3208.                     player.motion_clock = 0;
  3209.                     ++player.curr_frame;
  3210.  
  3211.                     // test frame range for left walking
  3212.  
  3213.                     if (player.curr_frame<4 || player.curr_frame>7)
  3214.                        {
  3215.                        player.curr_frame = 4;
  3216.  
  3217.                        } // end if out of frame range
  3218.  
  3219.                     // set translation factors
  3220.  
  3221.                     dx=-3;
  3222.  
  3223.                     // set direction
  3224.  
  3225.                     players_dir = PLAYER_WEST;
  3226.  
  3227.                     } // end if time to move
  3228.  
  3229.                  } // end if right
  3230.               else
  3231.               if (key_table[INDEX_RIGHT])  // move right
  3232.                    {
  3233.                    // only process if enough cycles have passed
  3234.  
  3235.                    if (++player.motion_clock==player.motion_speed)
  3236.                       {
  3237.  
  3238.                       player.motion_clock = 0;
  3239.                       ++player.curr_frame;
  3240.  
  3241.                       // test frame range for right walking
  3242.  
  3243.                       if (player.curr_frame<0 || player.curr_frame>3)
  3244.                          {
  3245.                          player.curr_frame = 0;
  3246.  
  3247.                          } // end if out of frame range
  3248.  
  3249.                       // set translation factors
  3250.  
  3251.                       dx=3;
  3252.  
  3253.                       // set direction
  3254.  
  3255.                       players_dir = PLAYER_EAST;
  3256.  
  3257.                       } // end if time to move
  3258.  
  3259.                    } // end if right
  3260.               else
  3261.               if (key_table[INDEX_UP])  // move up
  3262.                    {
  3263.                    // only process if enough cycles have passed
  3264.  
  3265.                    if (++player.motion_clock==player.motion_speed)
  3266.                       {
  3267.  
  3268.                       // test frame range for upward walking
  3269.  
  3270.                       player.motion_clock = 0;
  3271.                       ++player.curr_frame;
  3272.  
  3273.                       if (player.curr_frame<12 || player.curr_frame>15)
  3274.                          {
  3275.                          player.curr_frame = 12;
  3276.  
  3277.                          } // end if out of frame range
  3278.  
  3279.  
  3280.                       // set translation factors
  3281.  
  3282.                       dy=-3;
  3283.  
  3284.                       // set direction
  3285.  
  3286.                       players_dir = PLAYER_NORTH;
  3287.  
  3288.                       } // end if time to move
  3289.  
  3290.                    } // end if up
  3291.               else
  3292.               if (key_table[INDEX_DOWN]) // move down
  3293.                    {
  3294.                    // only process if enough cycles have passed
  3295.  
  3296.                    if (++player.motion_clock==player.motion_speed)
  3297.                       {
  3298.  
  3299.                       player.motion_clock = 0;
  3300.                       ++player.curr_frame;
  3301.  
  3302.                       // test frame range for downward motion
  3303.  
  3304.                       if (player.curr_frame<8 || player.curr_frame>11)
  3305.                          {
  3306.                          player.curr_frame = 8;
  3307.  
  3308.                          } // end if out of frame range
  3309.  
  3310.                       // set translation factors
  3311.  
  3312.                       dy=3;
  3313.  
  3314.                       // set direction
  3315.  
  3316.                       players_dir = PLAYER_SOUTH;
  3317.  
  3318.                       } // end if time to move
  3319.  
  3320.                    } // end if down
  3321.  
  3322.               if (key_table[INDEX_SPACE]) // fire an arrow
  3323.                    {
  3324.  
  3325.                    // are there any arrows left?
  3326.  
  3327.                    if (num_arrows>0)
  3328.                       {
  3329.  
  3330.                       Start_Arrow(player.x+4,
  3331.                                   player.y+4,
  3332.                                   arrow_vel_x[players_dir],
  3333.                                   arrow_vel_y[players_dir],
  3334.                                   players_dir);
  3335.  
  3336.                       } // end if any arrows
  3337.  
  3338.                    } // end if fire weapon
  3339.  
  3340.         } // end if kbhit
  3341.      else
  3342.      if (player.state==PLAYER_DYING && player.curr_frame <= 20)
  3343.         {
  3344.         // this code takes care of the death sequence
  3345.  
  3346.         // only animate if the time is right
  3347.  
  3348.         if (++player.motion_clock==player.motion_speed)
  3349.            {
  3350.            // reset motion clock
  3351.            player.motion_clock = 0;
  3352.  
  3353.            // test if death is over
  3354.  
  3355.            if (++player.curr_frame==21)
  3356.               {
  3357.               done=1;
  3358.               player.state=PLAYER_DEAD;
  3359.               player.curr_frame--;
  3360.               Delay(40);
  3361.  
  3362.               } // end if player is dead
  3363.  
  3364.            } // end if ok to animate
  3365.  
  3366.         } // end else if dying
  3367.  
  3368.      // test if player should be killed
  3369.  
  3370.      if (health==0 && !start_death)
  3371.         {
  3372.         // set player to dying
  3373.  
  3374.         player.state = PLAYER_DYING;
  3375.  
  3376.         // set up sprite structure
  3377.  
  3378.         player.curr_frame   = 16;
  3379.         player.motion_clock = 0;
  3380.         player.motion_speed = 5;
  3381.  
  3382.         // play his last words
  3383.  
  3384.         Play_Sound(SOUND_DEATH);
  3385.  
  3386.         // flag that player has moaned
  3387.  
  3388.         start_death=1;
  3389.  
  3390.         } // end if player has had it!
  3391.  
  3392.      // move everything
  3393.  
  3394.      Move_Arrows();
  3395.  
  3396.      Move_Fireballs();
  3397.  
  3398.      Animate_Explosions();
  3399.  
  3400.      Move_Bat();
  3401.  
  3402.      Move_Monsters();
  3403.  
  3404.      // translate player and perform collision detection
  3405.  
  3406.      player.x+=dx;
  3407.      player.y+=dy;
  3408.  
  3409.      // save old screen position
  3410.  
  3411.      old_screen_x = screen_x;
  3412.      old_screen_y = screen_y;
  3413.  
  3414.      // first test if player has moved off screen and we need to make a screen
  3415.      // change
  3416.  
  3417.      if (player.x>224-16)
  3418.          {
  3419.  
  3420.          if (++screen_x>3)
  3421.             {
  3422.             screen_x=3;
  3423.             player.x=224-16;
  3424.             }
  3425.          else
  3426.             {
  3427.             screen_change=1;
  3428.             player.x=0;
  3429.  
  3430.             } // end else warp
  3431.  
  3432.          } // end if off right edge
  3433.      else
  3434.      if (player.x<0)
  3435.          {
  3436.  
  3437.          if (--screen_x<0)
  3438.             {
  3439.  
  3440.             screen_x=0;
  3441.             player.x=0;
  3442.  
  3443.             }
  3444.          else
  3445.             {
  3446.             screen_change=1;
  3447.             player.x=224-16;
  3448.  
  3449.             } // end else warp
  3450.  
  3451.          } // end if off left edge
  3452.  
  3453.      if (player.y>190-16)
  3454.          {
  3455.  
  3456.          if (++screen_y>3)
  3457.             {
  3458.             screen_y=3;
  3459.             player.y=190-16;
  3460.             }
  3461.          else
  3462.             {
  3463.             screen_change=1;
  3464.             player.y=0;
  3465.  
  3466.             } // end else warp
  3467.  
  3468.          } // end if off bottom edge
  3469.      else
  3470.      if (player.y<0)
  3471.          {
  3472.  
  3473.          if (--screen_y<0)
  3474.             {
  3475.  
  3476.             screen_y=0;
  3477.             player.y=0;
  3478.  
  3479.             }
  3480.          else
  3481.             {
  3482.             screen_change=1;
  3483.             player.y=190-16;
  3484.  
  3485.             } // end else warp
  3486.  
  3487.          } // end if off top edge
  3488.  
  3489.      else
  3490.      {
  3491.  
  3492.      // obtain cell location of players feet since this is a pseudo 3-D view
  3493.      // and his feet are more meaningful than his center
  3494.  
  3495.      cell_x = (player.x+8)  >> 4;  // divide by 16 since cells are 16x16 pixels
  3496.      cell_y = (player.y+14) >> 4;
  3497.  
  3498.      // what is the cell at this location
  3499.  
  3500.      cell_id = world[screen_y][screen_x].cells[cell_y][cell_x];
  3501.  
  3502.      // is this cell a wall or obstruction?
  3503.  
  3504.      if (cell_id < 32)
  3505.         {
  3506.  
  3507.         // back player up
  3508.  
  3509.         player.x-=dx;
  3510.         player.y-=dy;
  3511.  
  3512.         } // end if hit obstacle
  3513.      else
  3514.         { // player must be touching either a floor tile or a potion, food..
  3515.  
  3516.         // test which id the player has touched
  3517.  
  3518.         switch(cell_id)
  3519.               {
  3520.  
  3521.               case SILVER_ID:
  3522.                    {
  3523.                    // increase amount of silver and update data structure
  3524.                    // along with visual bitmap
  3525.  
  3526.                    silver_pieces+=100+rand()%50;
  3527.  
  3528.                    // position bitmap and upodate screen
  3529.  
  3530.                    floors.x = cell_x << 4;
  3531.                    floors.y = cell_y << 4;
  3532.                    floors.curr_frame = 0;
  3533.                    SET_SPRITE_SIZE(16,16);
  3534.                    Draw_Sprite_DB((sprite_ptr)&floors);
  3535.  
  3536.                    // update database
  3537.  
  3538.                    world[screen_y][screen_x].cells[cell_y][cell_x] = FLOOR_1_ID;
  3539.  
  3540.                    // play a sound
  3541.  
  3542.                    Play_Sound(SOUND_MONEY );
  3543.  
  3544.                    } break;
  3545.  
  3546.               case GOLD_ID:
  3547.                    {
  3548.                    // increase amount of gold and update data structure
  3549.                    // along with visual bitmap
  3550.  
  3551.                    gold_pieces+=100+rand()%50;
  3552.  
  3553.                    // position bitmap and upodate screen
  3554.  
  3555.                    floors.x = cell_x << 4;
  3556.                    floors.y = cell_y << 4;
  3557.                    floors.curr_frame = 0;
  3558.                    SET_SPRITE_SIZE(16,16);
  3559.                    Draw_Sprite_DB((sprite_ptr)&floors);
  3560.  
  3561.                    // update database
  3562.  
  3563.                    world[screen_y][screen_x].cells[cell_y][cell_x] = FLOOR_1_ID;
  3564.  
  3565.                    // play a sound
  3566.  
  3567.                    Play_Sound(SOUND_MONEY  );
  3568.  
  3569.                    } break;
  3570.  
  3571.               case POTION_ID:
  3572.                    {
  3573.                    // increase number of potions and update data structure
  3574.                    // along with visual bitmap
  3575.  
  3576.                    number_potions++;
  3577.  
  3578.                    // position bitmap and upodate screen
  3579.  
  3580.                    floors.x = cell_x << 4;
  3581.                    floors.y = cell_y << 4;
  3582.                    floors.curr_frame = 0;
  3583.                    SET_SPRITE_SIZE(16,16);
  3584.                    Draw_Sprite_DB((sprite_ptr)&floors);
  3585.  
  3586.                    // update control panel
  3587.  
  3588.                    floors.x = 268;
  3589.                    floors.y = 176;
  3590.                    floors.curr_frame = 4;
  3591.                    Draw_Sprite_DB((sprite_ptr)&floors);
  3592.  
  3593.                    // update database
  3594.  
  3595.                    world[screen_y][screen_x].cells[cell_y][cell_x] = FLOOR_1_ID;
  3596.  
  3597.  
  3598.                    // play a sound
  3599.  
  3600.                    Play_Sound(SOUND_POTION);
  3601.  
  3602.                    } break;
  3603.  
  3604.               case FOOD_ID:
  3605.                    {
  3606.                    // increase amount of health and update data structure
  3607.                    // along with visual bitmap
  3608.  
  3609.                    health=health+10+rand()%5;
  3610.  
  3611.                    // max health out a 100 percent
  3612.  
  3613.                    if (health>100) health=100;
  3614.  
  3615.                    // position bitmap and upodate screen
  3616.  
  3617.                    floors.x = cell_x << 4;
  3618.                    floors.y = cell_y << 4;
  3619.                    floors.curr_frame = 0;
  3620.                    SET_SPRITE_SIZE(16,16);
  3621.                    Draw_Sprite_DB((sprite_ptr)&floors);
  3622.  
  3623.                    // update database
  3624.  
  3625.                    world[screen_y][screen_x].cells[cell_y][cell_x] = FLOOR_1_ID;
  3626.  
  3627.                    // play a sound
  3628.  
  3629.                    Play_Sound(SOUND_EAT  );
  3630.  
  3631.                    } break;
  3632.  
  3633.               case ARROWS_ID:
  3634.                    {
  3635.                    // increase number of arrows and update data structure
  3636.                    // along with visual bitmap
  3637.  
  3638.                    num_arrows+=10;
  3639.  
  3640.                    // position bitmap and upodate screen
  3641.  
  3642.                    floors.x = cell_x << 4;
  3643.                    floors.y = cell_y << 4;
  3644.                    floors.curr_frame = 0;
  3645.                    SET_SPRITE_SIZE(16,16);
  3646.                    Draw_Sprite_DB((sprite_ptr)&floors);
  3647.  
  3648.                    // update database
  3649.  
  3650.                    world[screen_y][screen_x].cells[cell_y][cell_x] = FLOOR_1_ID;
  3651.  
  3652.                    // play a sound
  3653.  
  3654.                    Play_Sound(SOUND_FARROW  );
  3655.  
  3656.                    } break;
  3657.  
  3658.              case EXIT_ID:  // archer is trying to exit
  3659.                   {
  3660.                   // exit if dagger found
  3661.  
  3662.                   if (dagger_found)
  3663.                       done=1;
  3664.  
  3665.                   } break;
  3666.  
  3667.              case DAGGER_ID: // player has found the dagger
  3668.                   {
  3669.  
  3670.                   // position bitmap and upodate screen
  3671.  
  3672.                   floors.x = cell_x << 4;
  3673.                   floors.y = cell_y << 4;
  3674.                   floors.curr_frame = 0;
  3675.                   SET_SPRITE_SIZE(16,16);
  3676.                   Draw_Sprite_DB((sprite_ptr)&floors);
  3677.  
  3678.                   // update control panel
  3679.  
  3680.                   floors.x = 268+18;
  3681.                   floors.y = 176;
  3682.                   floors.curr_frame = 8;
  3683.                   Draw_Sprite_DB((sprite_ptr)&floors);
  3684.  
  3685.                   // update database
  3686.  
  3687.                   world[screen_y][screen_x].cells[cell_y][cell_x] = FLOOR_1_ID;
  3688.  
  3689.                   // note that the dagger has been found
  3690.  
  3691.                   dagger_found=1;
  3692.  
  3693.                   // play the sound
  3694.  
  3695.                   Play_Sound(SOUND_DAGGER);
  3696.  
  3697.                   Delay(50);
  3698.  
  3699.                   // increase the players score
  3700.  
  3701.                   players_score+=1000;
  3702.  
  3703.                   } break;
  3704.  
  3705.               default:break;
  3706.  
  3707.               } // end switch
  3708.  
  3709.         } // end else test for special objects
  3710.  
  3711.      } // end else no screen warp
  3712.  
  3713.      // start things up here
  3714.  
  3715.      Control_Bat();
  3716.  
  3717.      // has there been a screen change
  3718.  
  3719.      if (screen_change)
  3720.         {
  3721.         // need to scroll over to the next page
  3722.  
  3723.         // kill all weapons
  3724.  
  3725.         Init_Arrows();
  3726.  
  3727.         Init_Fireballs();
  3728.  
  3729.         // kill any explosions
  3730.  
  3731.         Init_Explosions();
  3732.  
  3733.         // first save the monsters positions in the database
  3734.  
  3735.         Save_Monsters(old_screen_x,old_screen_y);
  3736.  
  3737.         // now draw the screen
  3738.  
  3739.         Draw_Screen(screen_x,screen_y);
  3740.  
  3741.         // now start the monsters
  3742.  
  3743.         Start_Monsters(screen_x,screen_y);
  3744.  
  3745.         } // end if screen change
  3746.  
  3747.      // scan background under objects
  3748.  
  3749.      SET_SPRITE_SIZE(16,16);
  3750.      Behind_Sprite_DB((sprite_ptr)&player);
  3751.  
  3752.      // scan under arrows
  3753.  
  3754.      Behind_Arrows();
  3755.  
  3756.      Behind_Fireballs();
  3757.  
  3758.      Behind_Explosions();
  3759.  
  3760.      Behind_Bat();
  3761.  
  3762.      Behind_Monsters();
  3763.  
  3764.      // draw objects
  3765.  
  3766.      Draw_Arrows();
  3767.  
  3768.      Draw_Fireballs();
  3769.  
  3770.      Draw_Monsters();
  3771.  
  3772.      // now draw the player
  3773.  
  3774.      SET_SPRITE_SIZE(16,16);
  3775.      Draw_Sprite_DB((sprite_ptr)&player);
  3776.  
  3777.      Draw_Explosions();
  3778.  
  3779.      Draw_Bat();
  3780.  
  3781.      // draw statistics
  3782.  
  3783.      Draw_Stats();
  3784.  
  3785.      // display double buffer
  3786.  
  3787.      Show_Double_Buffer((char far *)double_buffer);
  3788.  
  3789.      // do color effects
  3790.  
  3791.      Glow_Dagger();
  3792.  
  3793.      // wait a sec
  3794.  
  3795.      Delay(1);
  3796.  
  3797.      } // end while
  3798.  
  3799. // remove keyboard driver
  3800.  
  3801. Delete_Keyboard();
  3802.  
  3803. // were out of here, test if we should say the good message or the bad one
  3804.  
  3805. if (health==0 || !dagger_found || done==2)
  3806.    {
  3807.    // allow sound system to play a sound
  3808.  
  3809.    start_death=0;
  3810.  
  3811.    // play the end message
  3812.  
  3813.    Play_Sound(SOUND_END);
  3814.  
  3815.    // make sure player has heard it
  3816.  
  3817.    Delay(150);
  3818.  
  3819.    } // end if archer failed
  3820. else
  3821.    { // player did well
  3822.  
  3823.    // allow sound system to play a sound
  3824.  
  3825.    start_death=0;
  3826.  
  3827.    // play the goal message
  3828.  
  3829.    Play_Sound(SOUND_GOAL);
  3830.  
  3831.    // put up goal screen
  3832.  
  3833.    Do_Goal();
  3834.  
  3835.    } // put up happy screen
  3836.  
  3837. // exit system with a cool transition
  3838.  
  3839. Melt();
  3840.  
  3841. // reset the video mode back to text
  3842.  
  3843. Set_Video_Mode(TEXT_MODE);
  3844.  
  3845. // free the double buffer
  3846.  
  3847. Delete_Double_Buffer();
  3848.  
  3849. // close sound system
  3850.  
  3851. Close_Sound_System();
  3852.  
  3853. printf("\nVenture shut down...");
  3854. printf("\nAll resources released...exiting back to DOS.\n");
  3855.  
  3856. } // end main
  3857.  
  3858.  
  3859.