home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / appendix / mechs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-14  |  83.0 KB  |  3,517 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.  
  21.  
  22. // P R O T O T Y P E S //////////////////////////////////////////////////////
  23.  
  24. void Start_PDeath(void);
  25.  
  26. void Erase_PDeath(void);
  27.  
  28. void Animate_PDeath(void);
  29.  
  30. void Behind_PDeath(void);
  31.  
  32. void Draw_PDeath(void);
  33.  
  34. void Draw_Sprite_DBM(sprite_ptr sprite);
  35.  
  36. unsigned char Get_Pixel_DB(int x,int y);
  37.  
  38. void Blit_Char_G(int xc,int yc,char c,int color,int trans_flag);
  39.  
  40. void Blit_String_G(int x,int y,int color, char *string,int trans_flag);
  41.  
  42. void Blink_Lights(void);
  43.  
  44. void Energize(void);
  45.  
  46. void Start_Wave(void);
  47.  
  48. void Init_Mechs(void);
  49.  
  50. void Delete_Mechs(void);
  51.  
  52. void Move_Mechs(void);
  53.  
  54. void Erase_Mechs(void);
  55.  
  56. void Draw_Mechs(void);
  57.  
  58. void Behind_Mechs(void);
  59.  
  60. void Control_Mother(void);
  61.  
  62. void Move_Mother(void);
  63.  
  64. void Erase_Mother(void);
  65.  
  66. void Behind_Mother(void);
  67.  
  68. void Draw_Mother(void);
  69.  
  70. void Init_Stars(void);
  71.  
  72. void Move_Stars(void);
  73.  
  74. void Behind_Stars(void);
  75.  
  76. void Draw_Stars(void);
  77.  
  78. void Erase_Stars(void);
  79.  
  80. void Start_Missile(sprite_ptr who,
  81.                    int x,
  82.                    int y,
  83.                    int xv,
  84.                    int yv,
  85.                    int color,
  86.                    int tag);
  87.  
  88. void Erase_Missiles(void);
  89.  
  90. void Behind_Missiles(void);
  91.  
  92. void Draw_Missiles(void);
  93.  
  94. void Move_Missiles(void);
  95.  
  96. void Init_Missiles(void);
  97.  
  98. void Start_Explosion(int x,int y,int speed);
  99.  
  100. void Behind_Explosions(void);
  101.  
  102. void Erase_Explosions(void);
  103.  
  104. void Draw_Explosions(void);
  105.  
  106. void Animate_Explosions(void);
  107.  
  108. void Display_Instruments(void);
  109.  
  110. void Erase_Instruments(void);
  111.  
  112. void Play_Sound(int sound);
  113.  
  114. void _interrupt _far New_Key_Int(void);
  115.  
  116. // D E F I N E S /////////////////////////////////////////////////////////////
  117.  
  118. // begin keyboard stuff
  119.  
  120. #define KEYBOARD_INT    0x09        // the keyboard interrupt number
  121. #define KEY_BUFFER      0x60        // the buffer port
  122. #define KEY_CONTROL     0x61        // the controller port
  123. #define INT_CONTROL     0x20        // the interrupt controller
  124.  
  125. // make and break codes for the arrow keys, space and Q
  126.  
  127. #define MAKE_RIGHT       77
  128. #define MAKE_LEFT        75
  129.  
  130. #define MAKE_Q           16
  131. #define MAKE_SPACE       57
  132.  
  133.  
  134. #define BREAK_RIGHT      205
  135. #define BREAK_LEFT       203
  136.  
  137. #define BREAK_Q          144
  138. #define BREAK_SPACE      185
  139.  
  140. // indices into arrow key state table
  141.  
  142. #define INDEX_SPACE     0
  143. #define INDEX_Q         1
  144. #define INDEX_RIGHT     2
  145. #define INDEX_LEFT      3
  146.  
  147. // end keyboard
  148.  
  149.  
  150. #define PLAYER_DEATH_TIME    120    // how long it takes player to die
  151. #define NUM_DEATH_PARTICLES  30     // number of explosion particles in death
  152.  
  153.  
  154.  
  155. #define NUM_PATTERNS          4     // number of patterns mechs have
  156. #define MAX_PATTERN_ELEMENTS  60    // number of elements in a pattern
  157.  
  158. #define NUM_DIRECTIONS        9     // number of directions a mech can go
  159.  
  160. #define RED_BASE 32                 // start of the reds in default palette
  161.  
  162. #define BARRIER_START_COLOR 176     // the barrier color range
  163. #define BARRIER_END_COLOR   176+16
  164.  
  165.  
  166. // defines for starfield
  167.  
  168. #define NUM_STARS  50               // number of stars in the star field
  169.  
  170. #define PLANE_1    1
  171. #define PLANE_2    2
  172. #define PLANE_3    3
  173.  
  174. // constants for player and enemy
  175.  
  176. #define ENEMY_MISSILE  0
  177. #define PLAYER_MISSILE 1
  178. #define MISS_ALIVE     1
  179. #define MISS_DEAD      0
  180. #define NUM_MISSILES  30
  181.  
  182. // velocity of player
  183.  
  184. #define PLAYER_X_MOVE 6
  185. #define PLAYER_Y_MOVE 0
  186.  
  187. // player states
  188.  
  189. #define PLAYER_NOT_FIRING 0
  190. #define PLAYER_FIRING     1
  191.  
  192. #define PLAYER_DEAD       0
  193. #define PLAYER_ALIVE      1
  194. #define PLAYER_DYING      2
  195.  
  196. // general explosions
  197.  
  198. #define NUM_EXPLOSIONS    5         // numbre of explosions that can run at once
  199.  
  200. #define EXPLOSION_DEAD    0
  201. #define EXPLOSION_ALIVE   1
  202.  
  203.  
  204. // defines for mothership
  205.  
  206. #define MOTHER_DEAD       0
  207. #define MOTHER_ALIVE      1
  208.  
  209. #define MOTHER_RIGHT      1
  210. #define MOTHER_LEFT       0
  211.  
  212.  
  213. // defines for initial attack pattern
  214.  
  215. #define PATTERN_X_SIZE    7          // dimensions of pattern matrix
  216. #define PATTERN_Y_SIZE    5
  217. #define PATTERN_XO        48         // origin of pattern formation
  218. #define PATTERN_YO        16
  219.  
  220. #define NUM_ROBOT_FRAMES  10         // number of animation frames a mech has
  221.  
  222. // mech types
  223.  
  224. #define MECH_1            1
  225. #define MECH_2            2
  226. #define MECH_3            3
  227.  
  228. // states of mechs
  229.  
  230. #define MECH_DEAD         0 // dead
  231. #define MECH_ALIVE        1 // alive
  232. #define MECH_DYING        2 // dying
  233.  
  234. #define MECH_ATTACK       2 // action of attacking
  235. #define MECH_PATTERN      3 // action of pattern
  236. #define MECH_RETREAT      4 // looking for a place to stop
  237. #define MECH_FLOCK        5 // moving with others
  238. #define MECH_ROTATING     6 // mech is just spining
  239. #define MECH_ENERGIZING   7 // mech is energizing
  240.  
  241.  
  242. #define MECH_RIGHT        0 // mech moving to the right
  243. #define MECH_LEFT         1 // mech moving to the left
  244. #define MECH_UP           2 // mech moving up
  245. #define MECH_DOWN         3 // mech moving down
  246.  
  247. #define MAX_NUMBER_MECHS  20 // maximum number of mechs in game
  248.  
  249. #define NUMBER_WAVES      15
  250.  
  251. // sound stuff
  252.  
  253. #define NUM_SOUNDS 8
  254.  
  255. #define SOUND_MISSILE  0
  256. #define SOUND_EXPL1    1
  257. #define SOUND_EXPL2    2
  258. #define SOUND_EXPL3    3
  259. #define SOUND_KILL     4
  260. #define SOUND_ENERGY   5
  261. #define SOUND_READY    6
  262. #define SOUND_END      7
  263.  
  264. #define SOUND_DEFAULT_PORT  0x220  // default sound port for sound blaster
  265. #define SOUND_DEFAULT_INT   5      // default interrupt
  266.  
  267. // S T R U C T U R E S ///////////////////////////////////////////////////////
  268.  
  269. // typedef for a explosion particle and for a missile
  270.  
  271. typedef struct particle_typ
  272.         {
  273.         int x;                   // x position
  274.         int y;                   // y position
  275.         int xv;                  // x velocity
  276.         int yv;                  // y velocity
  277.         unsigned char color;     // the color of the particle
  278.         unsigned char back;      // the color behind the particle
  279.         int state;               // the state of the particle
  280.         int tag;                 // if the particle is a missile then who
  281.                                  // does it belong to?
  282.         int counter;             // use for counting
  283.         int threshold;           // the counters threshold
  284.  
  285.         int counter_2;
  286.         int threshold_2;
  287.  
  288.         } particle, *particle_ptr;
  289.  
  290.  
  291. // data structure for a single star
  292.  
  293. typedef struct star_typ
  294.         {
  295.         int x,y;              // position of star
  296.         int plane;            // which plane is star in
  297.         unsigned char color;  // color of star
  298.         unsigned char back;   // under star
  299.  
  300.         } star, *star_ptr;
  301.  
  302.  
  303. // data structure for mech
  304.  
  305. typedef struct mech_typ
  306.         {
  307.         int type;                 // type of mech 1,2,3
  308.         int x;                    // position of mech
  309.         int y;
  310.         int xv;                   // velocity of mech
  311.         int yv;
  312.         int state_1;              // state variables
  313.         int state_2;
  314.         int counter_1;            // counters
  315.         int counter_2;
  316.         int threshold_1;          // thresholds for counters
  317.         int threshold_2;
  318.         int aux_1;                // aux variables
  319.         int aux_2;
  320.         int new_state;            // the next state
  321.         int direction;            // direction of motion when flocking
  322.         int curr_frame;           // current animation frame
  323.         char far *background;     // background pointer
  324.  
  325.         } mech, *mech_ptr;
  326.  
  327.  
  328. // G L O B A L S  ////////////////////////////////////////////////////////////
  329.  
  330. // begin keyboard
  331.  
  332. void (_interrupt _far *Old_Isr)();  // holds old keyboard interrupt handler
  333.  
  334. int raw_key;                        // the global raw keyboard data
  335.  
  336. int key_table[4] = {0,0,0,0};      // the arrow key state table
  337.  
  338.  
  339. // end keyboard
  340.  
  341.  
  342. int cos_look[320];            // lookup table for cosines used for moving mother
  343.  
  344. long game_clock=0,            // how many ticks has current wave been running for
  345.      attack_time=500;         // threshold to start attack
  346.  
  347. star stars[NUM_STARS];        // the star field
  348.  
  349. particle pdeath[NUM_DEATH_PARTICLES]; // the particles used for player's death
  350.  
  351. // star field velocities
  352.  
  353. int velocity_1=2,             // the speeds of each plane
  354.     velocity_2=4,
  355.     velocity_3=6;
  356.  
  357. // pcx imagery
  358.  
  359. pcx_picture intro_pcx,        // the introduction and instructions
  360.             imagery_pcx,      // the game imagery
  361.             background_pcx;   // the backdrop
  362.  
  363. // the sprites used in the game
  364.  
  365. sprite player,                // the player
  366.        fire,                  // and explosion
  367.        mother,                // the mothership
  368.        robot_1,               // each robot type
  369.        robot_2,
  370.        robot_3;
  371.  
  372.  
  373. // variables pertaining to the player
  374.  
  375. long player_ships     = 3,    // number of ships the player has
  376.      player_energy    = 100,  // the initial energy of player's weapon
  377.      player_score     = 0,    // his score
  378.      player_gun_state = PLAYER_NOT_FIRING; // state of cannons
  379.  
  380. particle missiles[NUM_MISSILES];   // the array of missiles in the world
  381.  
  382. sprite explosions[NUM_EXPLOSIONS]; // the array of explosions
  383.  
  384. mech mech_array[MAX_NUMBER_MECHS]; // the mechs themselves
  385.  
  386. int energize_state = 0;            // state of wave, are the mech's energizing
  387.  
  388. int num_mechs      = 0;            // number of mechs for the current wave
  389. int wave_number    = 0;            // the wave number
  390. int mechs_killed   = 0;            // mechs killed thus far in current wave
  391.  
  392. int *current_wave;                 // pointer to current wave data
  393.  
  394.  
  395.  
  396. // these are the wave tables, there are used to place the mechs
  397.  
  398.  
  399. int wave_0[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,0,1,1,1,0,0,
  400.                                              0,0,2,2,2,0,0,
  401.                                              0,0,3,3,3,0,0,
  402.                                              0,0,0,0,0,0,0,
  403.                                              0,0,0,0,0,0,0};
  404.  
  405. int wave_1[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,1,0,0,0,1,0,
  406.                                              0,0,1,2,1,0,0,
  407.                                              0,3,3,3,3,3,0,
  408.                                              0,0,0,0,0,0,0,
  409.                                              0,0,0,0,0,0,0};
  410.  
  411.  
  412.  
  413.  
  414. int wave_2[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {2,0,2,3,2,0,2,
  415.                                              0,2,0,3,0,2,0,
  416.                                              0,0,3,3,3,0,0,
  417.                                              0,0,0,3,0,0,0,
  418.                                              0,0,0,0,0,0,0};
  419.  
  420. int wave_3[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,1,0,1,0,1,1,
  421.                                              1,1,0,0,0,1,1,
  422.                                              0,0,2,2,2,0,0,
  423.                                              0,3,3,3,3,3,0,
  424.                                              0,0,0,0,0,0,0};
  425.  
  426.  
  427.  
  428. int wave_4[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,0,3,3,3,0,0,
  429.                                              1,0,1,0,1,0,1,
  430.                                              2,1,2,1,2,1,2,
  431.                                              0,0,3,3,3,0,0,
  432.                                              0,0,0,3,0,0,0};
  433.  
  434.  
  435.  
  436. int wave_5[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,1,0,1,0,1,0,
  437.                                              0,0,3,3,3,0,0,
  438.                                              0,3,3,1,3,3,0,
  439.                                              0,3,2,2,2,3,0,
  440.                                              0,0,0,0,0,0,0};
  441.  
  442.  
  443.  
  444. int wave_6[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,2,3,3,3,2,1,
  445.                                              0,1,2,3,2,1,0,
  446.                                              0,0,1,2,1,0,0,
  447.                                              0,0,0,1,0,0,0,
  448.                                              0,0,0,0,0,0,0};
  449.  
  450.  
  451.  
  452. int wave_7[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,2,1,0,1,2,1,
  453.                                              0,1,0,0,0,1,0,
  454.                                              0,0,0,2,0,0,0,
  455.                                              0,0,3,3,3,0,0,
  456.                                              0,0,0,3,0,0,0};
  457.  
  458.  
  459. int wave_8[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,0,0,0,0,0,0,
  460.                                              2,2,2,2,2,2,2,
  461.                                              0,3,0,3,0,3,0,
  462.                                              0,0,0,0,0,0,0,
  463.                                              0,0,1,0,1,0,0};
  464.  
  465.  
  466.  
  467.  
  468. int wave_9[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,3,1,3,1,3,1,
  469.                                              1,0,1,0,1,0,1,
  470.                                              1,0,1,0,1,0,1,
  471.                                              0,2,0,2,0,2,0,
  472.                                              0,0,0,0,0,0,0};
  473.  
  474.  
  475. int wave_10[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,0,1,1,1,0,0,
  476.                                               0,0,2,2,2,0,0,
  477.                                               0,2,3,3,3,2,0,
  478.                                               2,3,0,0,0,3,2,
  479.                                               3,0,0,0,0,0,3};
  480.  
  481.  
  482.  
  483.  
  484. int wave_11[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {0,0,0,1,0,0,0,
  485.                                               0,0,1,2,1,0,0,
  486.                                               0,1,2,3,2,1,0,
  487.                                               0,0,1,2,1,0,0,
  488.                                               0,0,0,1,0,0,0};
  489.  
  490.  
  491.  
  492.  
  493.  
  494. int wave_12[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,2,1,0,1,2,1,
  495.                                               0,0,2,0,2,0,0,
  496.                                               0,0,1,3,1,0,0,
  497.                                               0,0,0,3,0,0,0,
  498.                                               0,0,0,3,0,0,0};
  499.  
  500. int wave_13[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,0,0,3,0,0,1,
  501.                                               0,0,2,0,2,0,0,
  502.                                               0,3,0,0,0,3,0,
  503.                                               0,0,2,0,2,0,0,
  504.                                               1,0,0,3,0,0,1};
  505.  
  506.  
  507.  
  508.  
  509. int wave_14[PATTERN_X_SIZE*PATTERN_Y_SIZE] = {1,1,1,0,3,0,0,
  510.                                               1,0,1,0,3,0,0,
  511.                                               1,1,1,2,3,0,0,
  512.                                               1,0,1,0,3,0,0,
  513.                                               1,0,1,0,3,3,3};
  514.  
  515. // this is an array that is used to point to all the wave tables
  516.  
  517. int *waves[NUMBER_WAVES];
  518.  
  519.  
  520. // this is a data structure that holds the instructions for the patterns
  521. // that the mechs take when in pattern mode
  522.  
  523. int patterns[NUM_PATTERNS][MAX_PATTERN_ELEMENTS]
  524.  
  525.     = {1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,6,6,7,7,7,7,8,8,8,8,7,7,7,7,7,7,6,6,7,5,4,4,3,3,2,2,1,1,0,0,0,-1,
  526.        1,1,1,1,1,1,1,1,1,1,2,2,3,3,4,4,5,5,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,8,8,8,8,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,-1,
  527.        1,1,8,8,7,7,8,8,7,7,7,7,7,7,7,7,6,6,5,5,4,4,3,3,3,3,3,3,3,3,4,4,4,4,5,5,6,6,7,7,7,7,7,7,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,-1,
  528.        1,1,2,2,3,3,3,3,3,3,3,3,4,4,5,5,5,5,5,5,6,6,7,7,7,7,7,7,7,7,7,8,8,1,1,1,1,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,1,1,0,0,0,0,-1};
  529.  
  530. // these are the velocity vectors used to move the mechs via a pattern instruction
  531.  
  532. int dirs_x[NUM_DIRECTIONS] = {0, 0, 4, 4, 4, 0,-4,-4,-4};
  533. int dirs_y[NUM_DIRECTIONS] = {0,-4,-4, 0, 4, 4, 4, 0,-4};
  534.  
  535. // sound stuff
  536.  
  537. char far *sound_fx[NUM_SOUNDS];
  538. unsigned char sound_lengths[NUM_SOUNDS];
  539.  
  540. int sound_available = 1;
  541.  
  542. int sound_port = SOUND_DEFAULT_PORT;  // default sound port
  543. int sound_int  = SOUND_DEFAULT_INT;   // default sound interrupt
  544.                                       // both read from mechs.cfg
  545.  
  546. // F U N C T I O N S //////////////////////////////////////////////////////////
  547.  
  548. void _interrupt _far New_Key_Int(void)
  549. {
  550.  
  551. // I'm in the mood for some inline!
  552.  
  553. _asm
  554.    {
  555.    sti                    ; re-enable interrupts
  556.    in al, KEY_BUFFER      ; get the key that was pressed
  557.    xor ah,ah              ; zero out upper 8 bits of AX
  558.    mov raw_key, ax        ; store the key in global
  559.    in al, KEY_CONTROL     ; set the control register
  560.    or al, 82h             ; set the proper bits to reset the FF
  561.    out KEY_CONTROL,al     ; send the new data back to the control register
  562.    and al,7fh
  563.    out KEY_CONTROL,al     ; complete the reset
  564.    mov al,20h
  565.    out INT_CONTROL,al     ; re-enable interrupts
  566.                           ; when this baby hits 88 mph, your gonna see
  567.                           ; some serious @#@#$%
  568.  
  569.    } // end inline assembly
  570.  
  571. // now for some C to update the arrow state table
  572.  
  573. // process the key and update the table
  574.  
  575. switch(raw_key)
  576.       {
  577.  
  578.       case MAKE_RIGHT: // pressing right
  579.            {
  580.            key_table[INDEX_RIGHT] = 1;
  581.            } break;
  582.  
  583.       case MAKE_LEFT:  // pressing left
  584.            {
  585.            key_table[INDEX_LEFT]  = 1;
  586.            } break;
  587.  
  588.       case MAKE_SPACE: // pressing space
  589.            {
  590.            key_table[INDEX_SPACE] = 1;
  591.            } break;
  592.  
  593.       case MAKE_Q:  // pressing Q
  594.            {
  595.            key_table[INDEX_Q]  = 1;
  596.            } break;
  597.  
  598.       case BREAK_RIGHT: // releasing right
  599.            {
  600.            key_table[INDEX_RIGHT] = 0;
  601.            } break;
  602.  
  603.       case BREAK_LEFT:  // releasing left
  604.            {
  605.            key_table[INDEX_LEFT]  = 0;
  606.            } break;
  607.  
  608.       case BREAK_SPACE: // releasing space
  609.            {
  610.            key_table[INDEX_SPACE] = 0;
  611.            } break;
  612.  
  613.       case BREAK_Q:  // releasing Q
  614.            {
  615.            key_table[INDEX_Q]  = 0;
  616.            } break;
  617.  
  618.       default: break;
  619.  
  620.       } // end switch
  621.  
  622. } // end New_Key_Int
  623.  
  624. ///////////////////////////////////////////////////////////////////////////////
  625.  
  626. int Initialize_Sound_System(void)
  627. {
  628.  
  629. FILE *fp;
  630.  
  631. // test if driver is on disk
  632.  
  633. if ( (fp=fopen("ct-voice.drv","rb") )==NULL)
  634.    {
  635.    return(0);
  636.    } // end if not file
  637.  
  638. fclose(fp);
  639.  
  640. // load up sound configuration file
  641.  
  642. if ( (fp=fopen("mechs.cfg","r"))==NULL )
  643.    {
  644.    printf("\nSound configuration file not found...");
  645.    printf("\nUsing default values of port 220h and interrupt 5.");
  646.  
  647.    } // end if open sound configuration file
  648. else
  649.    {
  650.  
  651.    fscanf(fp,"%d %d",&sound_port, &sound_int);
  652.    printf("\nSetting sound system to port %d decimal with interrupt %d.",
  653.                                                     sound_port, sound_int);
  654.  
  655.    } // end else
  656.  
  657. // start up the whole sound system and load everything
  658.  
  659. Voc_Load_Driver();
  660.  
  661. Voc_Set_Port(sound_port);
  662. Voc_Set_IRQ(sound_int);
  663. Voc_Init_Driver();
  664. Voc_Get_Version();
  665. Voc_Set_Status_Addr((char __far *)&ct_voice_status);
  666.  
  667. // load in sounds
  668.  
  669. sound_fx[SOUND_MISSILE ] = Voc_Load_Sound("missile.voc", &sound_lengths[SOUND_MISSILE ]);
  670. sound_fx[SOUND_EXPL1   ] = Voc_Load_Sound("expl1.voc",   &sound_lengths[SOUND_EXPL1   ]);
  671. sound_fx[SOUND_EXPL2   ] = Voc_Load_Sound("expl2.voc",   &sound_lengths[SOUND_EXPL2   ]);
  672. sound_fx[SOUND_EXPL3   ] = Voc_Load_Sound("expl3.voc",   &sound_lengths[SOUND_EXPL3   ]);
  673. sound_fx[SOUND_KILL    ] = Voc_Load_Sound("kill.voc",    &sound_lengths[SOUND_KILL    ]);
  674. sound_fx[SOUND_ENERGY  ] = Voc_Load_Sound("energy.voc",  &sound_lengths[SOUND_ENERGY  ]);
  675. sound_fx[SOUND_READY   ] = Voc_Load_Sound("ready.voc",   &sound_lengths[SOUND_READY   ]);
  676. sound_fx[SOUND_END     ] = Voc_Load_Sound("end.voc",     &sound_lengths[SOUND_END]);
  677.  
  678. Voc_Set_Speaker(1);
  679.  
  680. return(1);
  681.  
  682. } // end Initialize_Sound_System
  683.  
  684. /////////////////////////////////////////////////////////////////////////////
  685.  
  686. void Close_Sound_System(void)
  687. {
  688. // make sure there is sound
  689.  
  690. if (sound_available)
  691.    {
  692.  
  693.    Voc_Set_Speaker(0);
  694.  
  695.    // unload sounds
  696.  
  697.    Voc_Unload_Sound(sound_fx[SOUND_MISSILE ]);
  698.    Voc_Unload_Sound(sound_fx[SOUND_EXPL1   ]);
  699.    Voc_Unload_Sound(sound_fx[SOUND_EXPL2   ]);
  700.    Voc_Unload_Sound(sound_fx[SOUND_EXPL3   ]);
  701.    Voc_Unload_Sound(sound_fx[SOUND_KILL    ]);
  702.    Voc_Unload_Sound(sound_fx[SOUND_ENERGY  ]);
  703.    Voc_Unload_Sound(sound_fx[SOUND_READY   ]);
  704.    Voc_Unload_Sound(sound_fx[SOUND_END     ]);
  705.  
  706.    Voc_Terminate_Driver();
  707.  
  708.    } // end if sound
  709.  
  710. } // end Close_Sound_System
  711.  
  712. /////////////////////////////////////////////////////////////////////////////
  713.  
  714. void Play_Sound(int sound)
  715. {
  716.  
  717. if (sound_available)
  718.    {
  719.    Voc_Stop_Sound();
  720.    Voc_Play_Sound(sound_fx[sound] , sound_lengths[sound]);
  721.    } // end if sound available
  722.  
  723. } // end Play_Sound
  724.  
  725. ///////////////////////////////////////////////////////////////////////////////
  726.  
  727. void Start_PDeath(void)
  728. {
  729.  
  730. // this function begins the death of a player
  731.  
  732. int index;
  733.  
  734. // make sure the player is dying otherwise return
  735.  
  736. if (player.state!=PLAYER_DYING) return;
  737.  
  738. // loop thru all particles and initialize them to different upward velocities
  739.  
  740. for (index=0; index<NUM_DEATH_PARTICLES; index++)
  741.     {
  742.  
  743.     pdeath[index].x           =  9+player.x - 4 + rand()%9;
  744.     pdeath[index].y           =  9+player.y - 4 + rand()%9;
  745.     pdeath[index].xv          =  -5 + rand()%11;
  746.     pdeath[index].yv          =  -5-(rand()%7);
  747.     pdeath[index].color       =  137;
  748.     pdeath[index].back        =  0;
  749.     pdeath[index].state       =  0;
  750.     pdeath[index].tag         =  0;
  751.  
  752.     pdeath[index].counter     =  0;
  753.     pdeath[index].threshold   =  5;
  754.  
  755.     pdeath[index].counter_2   =  0;
  756.     pdeath[index].threshold_2 =  5;
  757.  
  758.  
  759.     } // end for index
  760.  
  761. Play_Sound(SOUND_EXPL1);
  762.  
  763. } // end Start_PDeath
  764.  
  765. ///////////////////////////////////////////////////////////////////////////////
  766.  
  767. void Erase_PDeath(void)
  768. {
  769. // this function is used to erase all the particles in the players death
  770.  
  771. int index;
  772.  
  773. // make sure the player is dying otherwise return
  774.  
  775. if (player.state!=PLAYER_DYING) return;
  776.  
  777. // loop thru all particles and erase them i.e. replace the background
  778.  
  779. for (index=0; index<NUM_DEATH_PARTICLES; index++)
  780.     {
  781.  
  782.     Plot_Pixel_Fast_DB(pdeath[index].x,pdeath[index].y,pdeath[index].back);
  783.  
  784.     } // end for index
  785.  
  786. } // end Erase_PDeath
  787.  
  788. ///////////////////////////////////////////////////////////////////////////////
  789.  
  790. void Animate_PDeath(void)
  791. {
  792.  
  793. // this is the workhorse of the death animation sequence, it moves the particles
  794. // applies gravity to them and changes their colors, also it bounds them to the
  795. // screen
  796.  
  797. int index;
  798.  
  799. // should we be doing this?
  800.  
  801. if (player.state!=PLAYER_DYING) return;
  802.  
  803. // process each particle
  804.  
  805. for (index=0; index<NUM_DEATH_PARTICLES; index++)
  806.     {
  807.  
  808.     // translation
  809.  
  810.     pdeath[index].x+=pdeath[index].xv;
  811.     pdeath[index].y+=pdeath[index].yv;
  812.  
  813.     // boundary tests
  814.  
  815.     // xtests
  816.  
  817.     if (pdeath[index].x > 319)
  818.        {
  819.        pdeath[index].x = 319;
  820.        }
  821.     else
  822.     if (pdeath[index].x < 0)
  823.        {
  824.        pdeath[index].x = 0;
  825.        }
  826.  
  827.     // ytests
  828.  
  829.     if (pdeath[index].y > 199)
  830.         {
  831.         pdeath[index].y     = 199;
  832.         pdeath[index].xv    = 0;
  833.         pdeath[index].color = 0;
  834.         }
  835.     else
  836.     if (pdeath[index].y < 1)
  837.         {
  838.         pdeath[index].y = 1;
  839.         }
  840.  
  841.     // gravity
  842.  
  843.     if (++pdeath[index].counter == pdeath[index].threshold)
  844.        {
  845.        // apply gravity field
  846.  
  847.        pdeath[index].yv++;
  848.  
  849.        // reset counter
  850.  
  851.        pdeath[index].counter = 0;
  852.  
  853.        } // end if time to apply gravity
  854.  
  855.     // color
  856.  
  857.     if (pdeath[index].y<199)
  858.        if (++pdeath[index].counter_2 == pdeath[index].threshold_2)
  859.           {
  860.           // change color
  861.  
  862.           pdeath[index].color++;
  863.  
  864.           // reset counter
  865.  
  866.           pdeath[index].counter_2 = 0;
  867.  
  868.           } // end if time to change color
  869.  
  870.     // end of sequence
  871.  
  872.     } // end for
  873.  
  874. // update death time
  875.  
  876. if (++player.anim_clock == PLAYER_DEATH_TIME)
  877.    {
  878.  
  879.    // reset players position
  880.  
  881.    player.x          = 160;
  882.    player.y          = 168;
  883.    player.curr_frame = 0;
  884.    player.state      = PLAYER_ALIVE;
  885.  
  886.    // clear all the missiles
  887.  
  888.    Init_Missiles();
  889.  
  890.    // reset the wave
  891.  
  892.    Start_Wave();
  893.  
  894.    } // end if player done dying
  895.  
  896. } // end Animate_PDeath
  897.  
  898. ///////////////////////////////////////////////////////////////////////////////
  899.  
  900. void Behind_PDeath(void)
  901. {
  902.  
  903. int index;
  904.  
  905. // check if we should do this
  906.  
  907. if (player.state!=PLAYER_DYING) return;
  908.  
  909. // loop thru all particles and scan their backgrounds
  910.  
  911. for (index=0; index<NUM_DEATH_PARTICLES; index++)
  912.     {
  913.  
  914.     pdeath[index].back = Get_Pixel_DB(pdeath[index].x,pdeath[index].y);
  915.  
  916.     } // end for index
  917.  
  918. } // end Behind_PDeath
  919.  
  920. ///////////////////////////////////////////////////////////////////////////////
  921.  
  922. void Draw_PDeath(void)
  923. {
  924.  
  925. int index;
  926.  
  927. // check if we should do this
  928.  
  929. if (player.state!=PLAYER_DYING) return;
  930.  
  931. // loop thru all particles and draw them
  932.  
  933. for (index=0; index<NUM_DEATH_PARTICLES; index++)
  934.     {
  935.  
  936.     Plot_Pixel_Fast_DB(pdeath[index].x,pdeath[index].y,pdeath[index].color);
  937.  
  938.     } // end for index
  939.  
  940. } // end Draw_PDeath
  941.  
  942. //////////////////////////////////////////////////////////////////////////////
  943.  
  944. void Draw_Sprite_DBM(sprite_ptr sprite)
  945. {
  946.  
  947. // this function draws a sprite on the screen row by row very quickly
  948. // note the use of shifting to implement multplication
  949. // also it is used as a special effect, the sprite drawn is melted by
  950. // randomly selecting red pixels
  951.  
  952.  
  953. char far *work_sprite;
  954. int work_offset=0,offset,x,y;
  955. unsigned char data;
  956.  
  957. // alias a pointer to sprite for ease of access
  958.  
  959. work_sprite = sprite->frames[sprite->curr_frame];
  960.  
  961. // compute offset of sprite in video buffer
  962.  
  963. offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  964.  
  965. for (y=0; y<sprite_height; y++)
  966.     {
  967.     // copy the next row into the double buffer using memcpy for speed
  968.  
  969.     for (x=0; x<sprite_width; x++)
  970.         {
  971.  
  972.         // test for transparent pixel i.e. 0, if not transparent then draw
  973.  
  974.         if ((work_sprite[work_offset+x]))
  975.              double_buffer[offset+x] = RED_BASE+rand()%32;
  976.  
  977.         } // end for x
  978.  
  979.     // move to next line in double buffer and in sprite bitmap buffer
  980.  
  981.     offset      += SCREEN_WIDTH;
  982.     work_offset += sprite_width;
  983.  
  984.     } // end for y
  985.  
  986. } // end Draw_Sprite_DBM
  987.  
  988. ///////////////////////////////////////////////////////////////////////////////
  989.  
  990. unsigned char Get_Pixel_DB(int x,int y)
  991. {
  992.  
  993. // gets the color value of pixel at (x,y) from the double buffer
  994.  
  995. return double_buffer[((y<<8) + (y<<6)) + x];
  996.  
  997. } // end Get_Pixel_DB
  998.  
  999. ///////////////////////////////////////////////////////////////////////////////
  1000.  
  1001. void Blit_Char_G(int xc,int yc,char c,int color,int trans_flag)
  1002. {
  1003. // this function uses the rom 8x8 character set to blit a character to the
  1004. // double buffer, also it blits the character in two colors
  1005.  
  1006. int offset,x,y;
  1007. unsigned char data;
  1008. char far *work_char;
  1009. unsigned char bit_mask = 0x80;
  1010.  
  1011. // compute starting offset in rom character lookup table
  1012.  
  1013. work_char = rom_char_set + c * CHAR_HEIGHT;
  1014.  
  1015. // compute offset of character in video buffer
  1016.  
  1017. offset = (yc << 8) + (yc << 6) + xc;
  1018.  
  1019. for (y=0; y<CHAR_HEIGHT; y++)
  1020.     {
  1021.     // reset bit mask
  1022.  
  1023.     bit_mask = 0x80;
  1024.  
  1025.     // test if it's time to change colors
  1026.  
  1027.     if (y==(CHAR_HEIGHT/2))
  1028.        color-=8; // change to lower intensity
  1029.  
  1030.     for (x=0; x<CHAR_WIDTH; x++)
  1031.         {
  1032.         // test for transparent pixel i.e. 0, if not transparent then draw
  1033.  
  1034.         if ((*work_char & bit_mask))
  1035.              video_buffer[offset+x] = color;
  1036.         else
  1037.         if (!trans_flag)  // takes care of transparency
  1038.             video_buffer[offset+x] = 0;
  1039.  
  1040.  
  1041.         // shift bit mask
  1042.  
  1043.         bit_mask = (bit_mask>>1);
  1044.  
  1045.         } // end for x
  1046.  
  1047.     // move to next line in video buffer and in rom character data area
  1048.  
  1049.     offset      += SCREEN_WIDTH;
  1050.     work_char++;
  1051.  
  1052.     } // end for y
  1053.  
  1054. } // end Blit_Char_G
  1055.  
  1056. //////////////////////////////////////////////////////////////////////////////
  1057.  
  1058. void Blit_String_G(int x,int y,int color, char *string,int trans_flag)
  1059. {
  1060. // this function blits an entire string to the double buffer
  1061. // It calls blit_char_g which is the gradient version of the character blitter
  1062.  
  1063. int index;
  1064.  
  1065. for (index=0; string[index]!=0; index++)
  1066.      {
  1067.  
  1068.      Blit_Char_G(x+(index<<3),y,string[index],color,trans_flag);
  1069.  
  1070.      } /* end while */
  1071.  
  1072. } /* end Blit_String_G */
  1073.  
  1074. //////////////////////////////////////////////////////////////////////////////
  1075.  
  1076. void Blink_Lights(void)
  1077. {
  1078. // this function blinks the lights on the barriers
  1079.  
  1080. static int clock=0,
  1081.            entered_yet=0;// used for timing, note: they are static!
  1082.  
  1083. static RGB_color color;
  1084.  
  1085. // this function blinks the running lights on the walkway
  1086.  
  1087. if (!entered_yet)
  1088.    {
  1089.  
  1090.    // reset the palette register 243 to light green
  1091.    // black, black
  1092.  
  1093.    color.red   = 0;
  1094.    color.green = 10;
  1095.    color.blue  = 0;
  1096.  
  1097.    Set_Palette_Register(243,(RGB_color_ptr)&color);
  1098.  
  1099.    // system has initialized, so flag it
  1100.  
  1101.    entered_yet=1;
  1102.  
  1103.    } // end if first time into function
  1104.  
  1105. // try and blick the lights, is it time
  1106.  
  1107.    ++clock;
  1108.  
  1109.    if (clock==4)
  1110.       {
  1111.       // turn the lights on
  1112.  
  1113.       color.green = 255;
  1114.  
  1115.       Set_Palette_Register(243,(RGB_color_ptr)&color);
  1116.  
  1117.       } // end if time to rotate
  1118.    else
  1119.    if (clock==8)
  1120.       {
  1121.  
  1122.       // turn the lights off
  1123.  
  1124.       color.green = 0;
  1125.  
  1126.       Set_Palette_Register(243,(RGB_color_ptr)&color);
  1127.  
  1128.       clock=0;
  1129.  
  1130.       } // end if time to blink
  1131.  
  1132. } // end Blink_Lights
  1133.  
  1134. ///////////////////////////////////////////////////////////////////////////////
  1135.  
  1136. void Energize(void)
  1137. {
  1138.  
  1139. // this function is used to slowly materialize the mechs, it does this by
  1140. // drwing them in separate bitmaps that are of a single color that can
  1141. // be controlled
  1142.  
  1143. static RGB_color color_grey,
  1144.                  color_red,
  1145.                  color_green;
  1146.  
  1147.  
  1148. // test if this is start of sequence
  1149.  
  1150. if (energize_state==0)
  1151.    {
  1152.  
  1153.    // the grey robot
  1154.  
  1155.    color_grey.red    = 0;
  1156.    color_grey.green  = 0;
  1157.    color_grey.blue   = 0;
  1158.  
  1159.    // the red robot
  1160.  
  1161.    color_red.red    = 0;
  1162.    color_red.green  = 0;
  1163.    color_red.blue   = 0;
  1164.  
  1165.  
  1166.    // the grey robot
  1167.  
  1168.    color_green.red    = 0;
  1169.    color_green.green  = 0;
  1170.    color_green.blue   = 0;
  1171.  
  1172.  
  1173.    // energizing has begun
  1174.  
  1175.    energize_state  = 1;
  1176.  
  1177.    Set_Palette_Register(240,(RGB_color_ptr)&color_grey);
  1178.    Set_Palette_Register(241,(RGB_color_ptr)&color_red);
  1179.    Set_Palette_Register(242,(RGB_color_ptr)&color_green);
  1180.  
  1181.    } // end if starting
  1182. else
  1183. if (rand()%2==1)
  1184.    {
  1185.    // update grey mechs
  1186.  
  1187.    ++color_grey.red;
  1188.    ++color_grey.green;
  1189.    ++color_grey.blue;
  1190.  
  1191.    // update red mechs
  1192.  
  1193.    ++color_red.red;
  1194.  
  1195.    // update green mechs
  1196.  
  1197.    ++color_green.green;
  1198.  
  1199.    // update the palette registers
  1200.  
  1201.    Set_Palette_Register(240,(RGB_color_ptr)&color_grey);
  1202.  
  1203.    Set_Palette_Register(241,(RGB_color_ptr)&color_red);
  1204.  
  1205.    Set_Palette_Register(242,(RGB_color_ptr)&color_green);
  1206.  
  1207.    } // end if time to increment color intensity
  1208.  
  1209. } // end Energize
  1210.  
  1211. ///////////////////////////////////////////////////////////////////////////////
  1212.  
  1213. void Start_Wave(void)
  1214. {
  1215.  
  1216. // this function is used to start a wave off
  1217.  
  1218. int x,y,mech_index=0,element, local_wave;
  1219.  
  1220. // reset number of mechs on this level
  1221.  
  1222. num_mechs=0;
  1223.  
  1224. // reset number of mechs killed
  1225.  
  1226. mechs_killed=0;
  1227.  
  1228. // select level
  1229.  
  1230. local_wave = wave_number;
  1231.  
  1232. // test to see if level is too high, if so choose randomly
  1233.  
  1234. if (local_wave>14)
  1235.    {
  1236.    // select wave randomly
  1237.  
  1238.    local_wave = rand()%10 + 5;
  1239.  
  1240.    // decrease the overall attack time of game now
  1241.  
  1242.    attack_time=-10;
  1243.  
  1244.    // test if we overflowed attack time
  1245.  
  1246.    if (attack_time<100)
  1247.       attack_time=100;
  1248.  
  1249.    } // end if did the first 15 waves
  1250.  
  1251. // alias data structure for current wave
  1252.  
  1253. current_wave = waves[local_wave];
  1254.  
  1255. // loop and create mechs
  1256.  
  1257. for (x=0; x<PATTERN_X_SIZE; x++)
  1258.     {
  1259.  
  1260.     for (y=0; y<PATTERN_Y_SIZE; y++)
  1261.         {
  1262.  
  1263.         // extract element out of database
  1264.  
  1265.         element = current_wave[PATTERN_X_SIZE*y + x];
  1266.  
  1267.         // test if this is a live mech
  1268.  
  1269.         if (element!=0)
  1270.            {
  1271.  
  1272.            // set fixed fields
  1273.  
  1274.            mech_array[num_mechs].x            = x * 32 + PATTERN_XO;
  1275.            mech_array[num_mechs].y            = y * 22 + PATTERN_YO;
  1276.  
  1277.            mech_array[num_mechs].xv           = 0;
  1278.            mech_array[num_mechs].yv           = 0;
  1279.            mech_array[num_mechs].state_1      = MECH_ALIVE;
  1280.            mech_array[num_mechs].state_2      = MECH_ENERGIZING;
  1281.            mech_array[num_mechs].counter_1    = 0;
  1282.            mech_array[num_mechs].counter_2    = 0;
  1283.            mech_array[num_mechs].aux_1        = 0;
  1284.            mech_array[num_mechs].aux_2        = 0;
  1285.            mech_array[num_mechs].threshold_1  = 0;
  1286.            mech_array[num_mechs].threshold_2  = 64;
  1287.            mech_array[num_mechs].direction    = 0;
  1288.            mech_array[num_mechs].curr_frame   = 9;
  1289.  
  1290.            // set type field
  1291.  
  1292.            mech_array[num_mechs].type         = element;
  1293.  
  1294.            // there is one more mech now
  1295.  
  1296.            num_mechs++;
  1297.  
  1298.            } // end if a live mech
  1299.  
  1300.         } // end for y
  1301.  
  1302.     } // end for x
  1303.  
  1304. // reset energizer colors
  1305.  
  1306. energize_state = 0;
  1307.  
  1308. // reset game clock
  1309.  
  1310. game_clock = 0;
  1311.  
  1312. // start things up
  1313.  
  1314. Energize();
  1315.  
  1316. // let's here some noise
  1317.  
  1318. if (player_ships>0)
  1319.     Play_Sound(SOUND_READY);
  1320.  
  1321.  
  1322. } // end Start_Wave
  1323.  
  1324. ///////////////////////////////////////////////////////////////////////////////
  1325.  
  1326. void Init_Mechs(void)
  1327. {
  1328.  
  1329. // this function is used to clear all the mechs and get them ready
  1330.  
  1331. int index;
  1332.  
  1333. for (index=0; index<MAX_NUMBER_MECHS; index++)
  1334.     {
  1335.     // zero out all the fields and allocate the memory
  1336.  
  1337.     mech_array[index].type        = 0;
  1338.     mech_array[index].x           = 0;
  1339.     mech_array[index].y           = 0;
  1340.     mech_array[index].xv          = 0;
  1341.     mech_array[index].yv          = 0;
  1342.     mech_array[index].state_1     = 0;
  1343.     mech_array[index].state_2     = 0;
  1344.     mech_array[index].aux_1       = 0;
  1345.     mech_array[index].aux_2       = 0;
  1346.     mech_array[index].new_state   = 0;
  1347.     mech_array[index].counter_1   = 0;
  1348.     mech_array[index].counter_2   = 0;
  1349.     mech_array[index].threshold_1 = 0;
  1350.     mech_array[index].threshold_2 = 0;
  1351.     mech_array[index].direction   = 0;
  1352.     mech_array[index].curr_frame  = 0;
  1353.     mech_array[index].background  =
  1354.                       (char far *)_fmalloc(sprite_width * sprite_height+1);
  1355.  
  1356.     } // end index
  1357.  
  1358. } // end Init_Mechs
  1359.  
  1360. ///////////////////////////////////////////////////////////////////////////////
  1361.  
  1362. void Delete_Mechs(void)
  1363. {
  1364.  
  1365. int index;
  1366.  
  1367. for (index=0; index<MAX_NUMBER_MECHS; index++)
  1368.     {
  1369.     _ffree(mech_array[index].background);
  1370.     } // end for index
  1371.  
  1372. } // end Delete_Mechs
  1373.  
  1374. ///////////////////////////////////////////////////////////////////////////////
  1375.  
  1376. void Move_Mechs(void)
  1377. {
  1378.  
  1379. // this is an extremely complex function is controls the mechs movement
  1380. // and their state machine transitions.  currently only pattern mode and
  1381. // flock mode are implemented
  1382.  
  1383. int index,                 // loop variable
  1384.     flock_switch=0,        // has the flock switched direction
  1385.     mech_killed_switch=0,  // has there been a death
  1386.     mdx=0,                 // the delta x
  1387.     curr_direction;        // current pattern direction
  1388.  
  1389. static int global_flock=MECH_RIGHT; // used to track the flock's direction
  1390.  
  1391. mech_ptr worker;                    // used as an alias to current mech
  1392.  
  1393. // loop process each mech
  1394.  
  1395. for (index=0; index<num_mechs; index++)
  1396.     {
  1397.  
  1398.     // alias current mech
  1399.  
  1400.     worker = (mech_ptr)&mech_array[index];
  1401.  
  1402.     // test state of mech
  1403.  
  1404.     if (worker->state_1==MECH_ALIVE)
  1405.        {
  1406.  
  1407.        // this is the hard part, based on state perform proper logic
  1408.  
  1409.        switch(worker->state_2)
  1410.              {
  1411.  
  1412.              case MECH_PATTERN: // process pattern mode
  1413.                   {
  1414.  
  1415.                   // test for start of state
  1416.  
  1417.                   if (worker->new_state)
  1418.                      {
  1419.                      // reset new state
  1420.  
  1421.                      worker->new_state=0;
  1422.  
  1423.                      // select a pattern and reset all vars
  1424.  
  1425.                      worker->aux_1     = rand()%NUM_PATTERNS;
  1426.  
  1427.                      // use counter 1 as index into pattern table
  1428.  
  1429.                      worker->counter_1 = 0;
  1430.                      worker->counter_2   = 0;
  1431.                      worker->threshold_2 = 2+rand()%3;
  1432.  
  1433.                      } // end if need to initialize state
  1434.  
  1435.                   // else must be continuing state
  1436.  
  1437.                   // access current direction
  1438.  
  1439.                   curr_direction = patterns[worker->aux_1][worker->counter_1];
  1440.  
  1441.                   // test if we are at end of sequence
  1442.  
  1443.                   if (curr_direction==-1)
  1444.                      {
  1445.                      worker->state_2    = MECH_FLOCK;
  1446.                      worker->new_state  = 1;
  1447.                      break;
  1448.  
  1449.                      } // end if at end
  1450.  
  1451.                   // extract current frame of animation
  1452.  
  1453.                   worker->curr_frame = curr_direction;
  1454.  
  1455.                   // using current direction, compute velocity vector
  1456.  
  1457.                   worker->x+=dirs_x[curr_direction];
  1458.                   worker->y+=dirs_y[curr_direction];
  1459.  
  1460.                   // test if we went too far
  1461.  
  1462.                   if (worker->x > 300 )
  1463.                      {
  1464.                      worker->x = 0;
  1465.                      }
  1466.                   else
  1467.                   if (worker->x < 0)
  1468.                      {
  1469.                      worker->x = 300;
  1470.                      }
  1471.  
  1472.                   if (worker->y >= 120)
  1473.                      worker->y = 120;
  1474.                   else
  1475.                   if (worker->y < 0)
  1476.                      worker->y = 0;
  1477.  
  1478.                   // move to next element in pattern
  1479.  
  1480.                   if (++worker->counter_2 == worker->threshold_2)
  1481.                      {
  1482.                      worker->counter_2=0;
  1483.                      worker->counter_1++;
  1484.  
  1485.                      } // end if time to switch pattern element
  1486.  
  1487.  
  1488.                   // test if we want to fire a missile
  1489.  
  1490.                   if ( (worker->x > (player.x - 60)) &&
  1491.                        (worker->x < (player.x + 80)) &&
  1492.                        (curr_direction>=4)   &&
  1493.                        (curr_direction<=6)   &&
  1494.                        (rand()%10==1) )
  1495.                      {
  1496.  
  1497.  
  1498.                      // start missile with current trajectory
  1499.  
  1500.  
  1501.                      Start_Missile((sprite_ptr)worker,
  1502.                                    worker->x+10,
  1503.                                    worker->y+sprite_height,
  1504.                                    dirs_x[curr_direction]*2,
  1505.                                    dirs_y[curr_direction]*2,
  1506.                                    9,
  1507.                                    ENEMY_MISSILE);
  1508.  
  1509.                      } // end if fire missile
  1510.  
  1511.  
  1512.                   } break;
  1513.  
  1514.              case MECH_ATTACK:  // mech attack mode (not implemented)
  1515.                   {
  1516.  
  1517.                   // test for start of state
  1518.  
  1519.                   if (worker->new_state)
  1520.                      {
  1521.  
  1522.  
  1523.  
  1524.  
  1525.                      } // end if need to initialize state
  1526.  
  1527.                   // else must be continuing state
  1528.  
  1529.                   } break;
  1530.  
  1531.              case MECH_RETREAT:  // mech retreat mode (not implemented)
  1532.                   {
  1533.  
  1534.                   // test for start of state
  1535.  
  1536.                   if (worker->new_state)
  1537.                      {
  1538.  
  1539.  
  1540.                      } // end if need to initialize state
  1541.  
  1542.  
  1543.                   // else must be continuing state
  1544.  
  1545.                   } break;
  1546.  
  1547.  
  1548.              case MECH_FLOCK:   // mech flock mode
  1549.                   {
  1550.  
  1551.                   // test for start of state
  1552.  
  1553.                   if (worker->new_state)
  1554.                      {
  1555.                      // reset new state
  1556.  
  1557.                      worker->new_state=0;
  1558.  
  1559.                      // select a pattern and reset all vars
  1560.  
  1561.                      worker->counter_2    = 0;
  1562.                      worker->threshold_2  = 4;
  1563.                      worker->direction    = global_flock;
  1564.  
  1565.                      } // end if need to initialize state
  1566.  
  1567.  
  1568.                   // motion
  1569.  
  1570.                   if (worker->direction==MECH_RIGHT)
  1571.                      {
  1572.  
  1573.                      // do translation
  1574.  
  1575.                      worker->x+=(worker->xv);
  1576.  
  1577.                      // test right boundary
  1578.  
  1579.                      if (worker->x > SCREEN_WIDTH-32)
  1580.                         flock_switch=1;
  1581.  
  1582.                      } // end if moving right
  1583.                   else
  1584.                   if (worker->direction==MECH_LEFT)
  1585.                      {
  1586.                      // do translation
  1587.  
  1588.                      worker->x-=(worker->xv);
  1589.  
  1590.                      // test left boundary
  1591.  
  1592.                      if (worker->x < 32-18)
  1593.                         flock_switch=1;
  1594.  
  1595.                      } // end if moving left
  1596.  
  1597.  
  1598.                   // animation
  1599.  
  1600.                   if (++worker->counter_2 == worker->threshold_2)
  1601.                      {
  1602.                      // reset counter
  1603.  
  1604.                      worker->counter_2 = 0;
  1605.  
  1606.                      if (++worker->curr_frame > 1)
  1607.                         worker->curr_frame=0;
  1608.  
  1609.                      } // end if time to change frames
  1610.  
  1611.  
  1612.                   // weapons
  1613.  
  1614.                   if ( (worker->x > (player.x - 50)) &&
  1615.                        (worker->x < (player.x + 70)) &&
  1616.                        (rand()%50==1) )
  1617.                      {
  1618.  
  1619.  
  1620.                      // compute trajectory
  1621.  
  1622.                      if (worker->x < player.x - 10)
  1623.                         mdx=+3;
  1624.                      else
  1625.                      if (worker->x > player.x + 30)
  1626.                         mdx=-3;
  1627.                      else
  1628.                         mdx=0;
  1629.  
  1630.                      // the the missile with computed trajectory velocity
  1631.  
  1632.                      Start_Missile((sprite_ptr)worker,
  1633.                                    worker->x+10,
  1634.                                    worker->y+sprite_height,
  1635.                                    mdx,
  1636.                                    6,
  1637.                                    9,
  1638.                                    ENEMY_MISSILE);
  1639.  
  1640.                      } // end if time to fire
  1641.  
  1642.                   // test if it's time to blow this coup!
  1643.  
  1644.                   if (game_clock>attack_time && rand()%100==1)
  1645.                      {
  1646.  
  1647.                      // switch state to pattern
  1648.  
  1649.                      worker->state_2    = MECH_PATTERN;
  1650.                      worker->new_state  = 1;
  1651.  
  1652.                      if (rand()%5==1)
  1653.                         Play_Sound(SOUND_KILL);
  1654.  
  1655.                      } // end if time to switch to pattern state
  1656.  
  1657.                   } break;
  1658.  
  1659.  
  1660.              case MECH_ROTATING:  // not implemented
  1661.                   {
  1662.  
  1663.                   } break;
  1664.  
  1665.  
  1666.              case MECH_ENERGIZING:  // the initial start up state of mechs
  1667.                   {
  1668.  
  1669.                   // increment energizer time
  1670.  
  1671.                   worker->counter_2++;
  1672.  
  1673.                   // test if we are done energizing
  1674.  
  1675.                   if (worker->counter_2 < worker->threshold_2)
  1676.                      {
  1677.                      // continue energizing
  1678.  
  1679.  
  1680.                      } // end if still energizing
  1681.                   else
  1682.                      {
  1683.                      // need to move to flock state
  1684.  
  1685.                      worker->state_2      = MECH_FLOCK;
  1686.                      worker->xv           = 2;
  1687.                      worker->counter_2    = 0;
  1688.                      worker->threshold_2  = 4;
  1689.                      worker->direction    = MECH_RIGHT;
  1690.                      worker->curr_frame   = 0;
  1691.  
  1692.                      // move out of energizing state
  1693.  
  1694.                      ++energize_state;
  1695.  
  1696.                      } // end else move to flock state
  1697.  
  1698.                   } break;
  1699.  
  1700.              default:break;
  1701.  
  1702.              } // end switch state_2
  1703.  
  1704.        } // end if alive
  1705.     else
  1706.     if (mech_array[index].state_1==MECH_DYING)  // test if mech is dying
  1707.        {
  1708.        // one more frame of death
  1709.  
  1710.        if (++worker->counter_1 > worker->threshold_1)
  1711.           {
  1712.  
  1713.           worker->state_1 = MECH_DEAD;
  1714.           mechs_killed++;
  1715.           mech_killed_switch=1;
  1716.  
  1717.           // were getting killed, let's get more agressive!
  1718.  
  1719.           game_clock+=25;
  1720.  
  1721.           } // end if done dying
  1722.  
  1723.        } // end if alive
  1724.  
  1725.     } // end for index
  1726.  
  1727. // processed all mechs now do any global updates
  1728.  
  1729. // test if we need to flip the whole crew around
  1730.  
  1731. if (flock_switch==1)
  1732. {
  1733.  
  1734. // loop thru all mechs
  1735.  
  1736. for (index=0; index<num_mechs; index++)
  1737.     {
  1738.  
  1739.     // alias pointer to current mech
  1740.  
  1741.     worker = (mech_ptr)&mech_array[index];
  1742.  
  1743.     // test if mech is alive and flocking
  1744.  
  1745.     if (worker->state_1 == MECH_ALIVE &&
  1746.         worker->state_2 == MECH_FLOCK )
  1747.        {
  1748.        // switch directions
  1749.  
  1750.        if (worker->direction==MECH_RIGHT)
  1751.            {
  1752.            global_flock = MECH_LEFT;
  1753.            worker->direction=MECH_LEFT;
  1754.            }
  1755.        else // else must be right
  1756.            {
  1757.            global_flock = MECH_RIGHT;
  1758.            worker->direction=MECH_RIGHT;
  1759.            }
  1760.  
  1761.        } // end if alive
  1762.  
  1763.     } // end for index global
  1764.  
  1765. } // end if global change
  1766.  
  1767. // test if someone has been killed
  1768.  
  1769. if (mech_killed_switch==1)
  1770. {
  1771.  
  1772. // loop thru them all
  1773.  
  1774. for (index=0; index<num_mechs; index++)
  1775.     {
  1776.  
  1777.     // alias for speed
  1778.  
  1779.     worker = (mech_ptr)&mech_array[index];
  1780.  
  1781.     // if it was a flocker then crank up velocity and move down a little
  1782.  
  1783.     if (worker->state_1 == MECH_ALIVE &&
  1784.         worker->state_2 == MECH_FLOCK )
  1785.        {
  1786.  
  1787.        // increase acceleration
  1788.  
  1789.        if (++worker->xv > 6)
  1790.           worker->xv=6;
  1791.  
  1792.        // move them down a little
  1793.  
  1794.        worker->y+=2;
  1795.  
  1796.        } // end if alive
  1797.  
  1798.     } // end for index global
  1799.  
  1800. } // end if global change
  1801.  
  1802.  
  1803. // test if mechs are energizing, if so call energizing function to
  1804. // perform special fX
  1805.  
  1806. if (energize_state==1)
  1807.    Energize();
  1808.  
  1809. } // end Move_Mechs
  1810.  
  1811. ///////////////////////////////////////////////////////////////////////////////
  1812.  
  1813. void Erase_Mechs(void)
  1814. {
  1815.  
  1816. // this function erases all the mechs
  1817.  
  1818. int index;
  1819.  
  1820. // loop thru all mechs
  1821.  
  1822. for (index=0; index<num_mechs; index++)
  1823.     {
  1824.  
  1825.     // based on type of mech use proper animation frames
  1826.  
  1827.     // test if mech is alive
  1828.  
  1829.     if (mech_array[index].state_1 != MECH_DEAD)
  1830.        {
  1831.  
  1832.        // need to know which mech type so correct bitmaps can be used
  1833.  
  1834.        switch(mech_array[index].type)
  1835.              {
  1836.  
  1837.              case MECH_1:   // type one mech
  1838.                   {
  1839.                   robot_1.x          = mech_array[index].x;
  1840.                   robot_1.y          = mech_array[index].y;
  1841.                   robot_1.background = mech_array[index].background;
  1842.  
  1843.                   Erase_Sprite_DB((sprite_ptr)&robot_1);
  1844.  
  1845.                   } break;
  1846.  
  1847.              case MECH_2:   // type two mech
  1848.                   {
  1849.                   robot_2.x          = mech_array[index].x;
  1850.                   robot_2.y          = mech_array[index].y;
  1851.                   robot_2.background = mech_array[index].background;
  1852.  
  1853.                   Erase_Sprite_DB((sprite_ptr)&robot_2);
  1854.  
  1855.                   } break;
  1856.  
  1857.              case MECH_3:   // type three mech
  1858.                   {
  1859.                   robot_3.x          = mech_array[index].x;
  1860.                   robot_3.y          = mech_array[index].y;
  1861.                   robot_3.background = mech_array[index].background;
  1862.  
  1863.                   Erase_Sprite_DB((sprite_ptr)&robot_3);
  1864.  
  1865.                   } break;
  1866.  
  1867.              default:break;
  1868.  
  1869.              } // end switch
  1870.  
  1871.        } // end if mech dead
  1872.  
  1873.     } // end for index
  1874.  
  1875. } // end Erase_Mechs
  1876.  
  1877. ///////////////////////////////////////////////////////////////////////////////
  1878.  
  1879. void Draw_Mechs(void)
  1880. {
  1881.  
  1882. // this function draws the mechs
  1883.  
  1884. int index;
  1885.  
  1886. // process each mech
  1887.  
  1888. for (index=0; index<num_mechs; index++)
  1889.     {
  1890.  
  1891.     // test if mech is alive
  1892.  
  1893.     if (mech_array[index].state_1 != MECH_DEAD)
  1894.        {
  1895.  
  1896.        switch(mech_array[index].type)
  1897.              {
  1898.  
  1899.              case MECH_1:   // type one mech
  1900.                   {
  1901.                   robot_1.x          = mech_array[index].x;
  1902.                   robot_1.y          = mech_array[index].y;
  1903.                   robot_1.curr_frame = mech_array[index].curr_frame;
  1904.  
  1905.                   // test if we should use dying blitter
  1906.  
  1907.                   if (mech_array[index].state_1==MECH_ALIVE)
  1908.                      Draw_Sprite_DB((sprite_ptr)&robot_1);
  1909.                   else // use melter draw
  1910.                      Draw_Sprite_DBM((sprite_ptr)&robot_1);
  1911.  
  1912.                   } break;
  1913.  
  1914.              case MECH_2: // type two mech
  1915.                   {
  1916.                   robot_2.x          = mech_array[index].x;
  1917.                   robot_2.y          = mech_array[index].y;
  1918.                   robot_2.curr_frame = mech_array[index].curr_frame;
  1919.  
  1920.                   // test if we should use dying blitter
  1921.  
  1922.                   if (mech_array[index].state_1==MECH_ALIVE)
  1923.                      Draw_Sprite_DB((sprite_ptr)&robot_2);
  1924.                   else // use melter draw
  1925.                      Draw_Sprite_DBM((sprite_ptr)&robot_2);
  1926.  
  1927.                   } break;
  1928.  
  1929.              case MECH_3:    // type three mech
  1930.                   {
  1931.                   robot_3.x          = mech_array[index].x;
  1932.                   robot_3.y          = mech_array[index].y;
  1933.                   robot_3.curr_frame = mech_array[index].curr_frame;
  1934.  
  1935.                   // test if we should use dying blitter
  1936.  
  1937.                   if (mech_array[index].state_1==MECH_ALIVE)
  1938.                      Draw_Sprite_DB((sprite_ptr)&robot_3);
  1939.                   else // use melter draw
  1940.                      Draw_Sprite_DBM((sprite_ptr)&robot_3);
  1941.  
  1942.                   } break;
  1943.  
  1944.              default:break;
  1945.  
  1946.              } // end switch
  1947.  
  1948.        } // end if mech dead
  1949.  
  1950.     } // end for index
  1951.  
  1952. } // end Draw_Mechs
  1953.  
  1954. //////////////////////////////////////////////////////////////////////////////
  1955.  
  1956. void Behind_Mechs(void)
  1957. {
  1958. // this function scans the background under the mechs
  1959.  
  1960. int index;
  1961.  
  1962. // loop and process all mechs
  1963.  
  1964. for (index=0; index<num_mechs; index++)
  1965.     {
  1966.  
  1967.     // test if mech is alive
  1968.  
  1969.     if (mech_array[index].state_1 != MECH_DEAD)
  1970.        {
  1971.  
  1972.        switch(mech_array[index].type)
  1973.              {
  1974.  
  1975.              case MECH_1:   // type one mech
  1976.                   {
  1977.                   robot_1.x          = mech_array[index].x;
  1978.                   robot_1.y          = mech_array[index].y;
  1979.                   robot_1.background = mech_array[index].background;
  1980.  
  1981.                   Behind_Sprite_DB((sprite_ptr)&robot_1);
  1982.  
  1983.                   } break;
  1984.  
  1985.              case MECH_2:   // type two mech
  1986.                   {
  1987.                   robot_2.x          = mech_array[index].x;
  1988.                   robot_2.y          = mech_array[index].y;
  1989.                   robot_2.background = mech_array[index].background;
  1990.  
  1991.                   Behind_Sprite_DB((sprite_ptr)&robot_2);
  1992.  
  1993.                   } break;
  1994.  
  1995.              case MECH_3:   // type three mech
  1996.                   {
  1997.                   robot_3.x          = mech_array[index].x;
  1998.                   robot_3.y          = mech_array[index].y;
  1999.                   robot_3.background = mech_array[index].background;
  2000.  
  2001.                   Behind_Sprite_DB((sprite_ptr)&robot_3);
  2002.  
  2003.                   } break;
  2004.  
  2005.              default:break;
  2006.  
  2007.              } // end switch
  2008.  
  2009.        } // end if mech dead
  2010.  
  2011.     } // end for index
  2012.  
  2013. } // end Behind_Mechs
  2014.  
  2015. //////////////////////////////////////////////////////////////////////////////
  2016.  
  2017. void Control_Mother(void)
  2018. {
  2019.  
  2020. // this function controls the mother ship
  2021.  
  2022. if (mother.state == MOTHER_DEAD && rand()%500==1)
  2023.    {
  2024.  
  2025.    // turn on the mother ship
  2026.  
  2027.    mother.state = MOTHER_ALIVE;
  2028.  
  2029.    // select a random direction
  2030.  
  2031.    switch(rand()%2)
  2032.          {
  2033.  
  2034.          case 0:  // right
  2035.                {
  2036.  
  2037.                mother.curr_frame   = MOTHER_RIGHT;
  2038.                mother.motion_speed = 4+rand()%2;
  2039.                mother.x            = 0;
  2040.                mother.y            = 12+rand()%16;
  2041.  
  2042.                } break;
  2043.  
  2044.          case 1: // left
  2045.                {
  2046.  
  2047.                mother.curr_frame   = MOTHER_LEFT;
  2048.                mother.motion_speed = -(4+rand()%2);
  2049.                mother.x            = SCREEN_WIDTH-20;
  2050.                mother.y            = 12+rand()%16;
  2051.  
  2052.  
  2053.                } break;
  2054.  
  2055.  
  2056.          default:break;
  2057.  
  2058.          } // end switch
  2059.  
  2060.     Behind_Sprite_DB((sprite_ptr)&mother);
  2061.  
  2062.    } // end if start mother up
  2063.  
  2064. } // end Control_Mother
  2065.  
  2066. ///////////////////////////////////////////////////////////////////////////////
  2067.  
  2068. void Move_Mother(void)
  2069. {
  2070.  
  2071. // this moves the mother ship if it is alive
  2072.  
  2073. if (mother.state == MOTHER_ALIVE)
  2074.    {
  2075.  
  2076.    // move x at a constant speed
  2077.  
  2078.    mother.x+=mother.motion_speed;
  2079.  
  2080.    // modulate the y position by a cosine wave
  2081.  
  2082.    mother.y+=cos_look[mother.x];
  2083.  
  2084.    // do boundary collisions
  2085.  
  2086.    if (mother.y<0) mother.y=0;
  2087.  
  2088.    if (mother.x > SCREEN_WIDTH-20 || mother.x < 0)
  2089.       mother.state = MOTHER_DEAD;
  2090.  
  2091.    } // end if alive
  2092.  
  2093. } // end Move_Mother
  2094.  
  2095. //////////////////////////////////////////////////////////////////////////////
  2096.  
  2097. void Erase_Mother(void)
  2098. {
  2099.  
  2100. // this function erases the mother ship
  2101.  
  2102. if (mother.state == MOTHER_ALIVE)
  2103.    {
  2104.  
  2105.    Erase_Sprite_DB((sprite_ptr)&mother);
  2106.  
  2107.    } // end if alive
  2108.  
  2109. } // end Erase_Mother
  2110.  
  2111. //////////////////////////////////////////////////////////////////////////////
  2112.  
  2113. void Behind_Mother(void)
  2114. {
  2115.  
  2116. // this function scans the background under the mothership
  2117.  
  2118. if (mother.state == MOTHER_ALIVE)
  2119.    {
  2120.  
  2121.    Behind_Sprite_DB((sprite_ptr)&mother);
  2122.  
  2123.    } // end if alive
  2124.  
  2125. } // end Behind_Mother
  2126.  
  2127. //////////////////////////////////////////////////////////////////////////////
  2128.  
  2129. void Draw_Mother(void)
  2130. {
  2131.  
  2132. // this function draws the mothership
  2133.  
  2134. if (mother.state == MOTHER_ALIVE)
  2135.    {
  2136.  
  2137.    Draw_Sprite_DB((sprite_ptr)&mother);
  2138.  
  2139.    } // end if alive
  2140.  
  2141. } // end Draw_Mother
  2142.  
  2143. //////////////////////////////////////////////////////////////////////////////
  2144.  
  2145. void Init_Stars(void)
  2146. {
  2147.  
  2148. // this function will initialize the star field
  2149.  
  2150. int index;
  2151.  
  2152. // for each star choose a position, plane and color
  2153.  
  2154. for (index=0; index<NUM_STARS; index++)
  2155.     {
  2156.     // initialize each star to a velocity, position and color
  2157.  
  2158.     stars[index].x     = rand()%320;
  2159.     stars[index].y     = rand()%180;
  2160.  
  2161.     // decide what star plane the star is in
  2162.  
  2163.     switch(rand()%3)
  2164.           {
  2165.           case 0: // plane 1- the farthest star plane
  2166.                {
  2167.                // set velocity and color
  2168.  
  2169.                stars[index].plane = 1;
  2170.                stars[index].color = 8;
  2171.  
  2172.                } break;
  2173.  
  2174.           case 1: // plane 2-The medium distance star plane
  2175.                {
  2176.  
  2177.                stars[index].plane = 2;
  2178.                stars[index].color = 7;
  2179.  
  2180.                } break;
  2181.  
  2182.           case 2: // plane 3-The nearest star plane
  2183.                {
  2184.  
  2185.                stars[index].plane = 3;
  2186.                stars[index].color = 15;
  2187.  
  2188.                } break;
  2189.  
  2190.           } // end switch
  2191.  
  2192.     } // end for index
  2193.  
  2194. } // end Init_Stars
  2195.  
  2196. ////////////////////////////////////////////////////////////////////////////////
  2197.  
  2198. void Move_Stars(void)
  2199. {
  2200.  
  2201. int index;
  2202.  
  2203.  
  2204. // move the star fields
  2205.  
  2206. for (index=0; index<NUM_STARS; index++)
  2207.     {
  2208.  
  2209.     // move the star and test for off screen condition
  2210.  
  2211.     // each star is in a different plane so test which plane star is
  2212.     // in so that proper velocity may be used
  2213.  
  2214.     switch(stars[index].plane)
  2215.           {
  2216.           case PLANE_1: // the slowest plane
  2217.                {
  2218.                stars[index].y+=velocity_1;
  2219.                } break;
  2220.  
  2221.           case PLANE_2: // the medium speed plane
  2222.                {
  2223.                stars[index].y+=velocity_2;
  2224.                } break;
  2225.  
  2226.           case PLANE_3: // the fastest plane (near)
  2227.                {
  2228.                stars[index].y+=velocity_3;
  2229.                } break;
  2230.  
  2231.            } // end switch
  2232.  
  2233.     // test if star went off screen
  2234.  
  2235.     if (stars[index].y > 179 )
  2236.        stars[index].y=(stars[index].y-180); // wrap around
  2237.     else
  2238.     if (stars[index].y < 0) // off left edge?
  2239.         stars[index].y = (180+stars[index].y); // wrap around
  2240.  
  2241.  
  2242.     } // end for index
  2243.  
  2244. } // end Move_Stars
  2245.  
  2246. ////////////////////////////////////////////////////////////////////////////////
  2247.  
  2248. void Behind_Stars(void)
  2249. {
  2250. // this function scans the background under the stars
  2251.  
  2252. int index;
  2253.  
  2254. for (index=0; index<NUM_STARS; index++)
  2255.     {
  2256.  
  2257.     stars[index].back = Get_Pixel_DB(stars[index].x,stars[index].y);
  2258.  
  2259.     } // end for index
  2260.  
  2261. } // end Behind_Stars
  2262.  
  2263. ////////////////////////////////////////////////////////////////////////////////
  2264.  
  2265. void Draw_Stars(void)
  2266. {
  2267.  
  2268. // this function draws the stars
  2269.  
  2270. int index;
  2271.  
  2272. for (index=0; index<NUM_STARS; index++)
  2273.     {
  2274.  
  2275.     Plot_Pixel_Fast_DB(stars[index].x,stars[index].y,stars[index].color);
  2276.  
  2277.     } // end for index
  2278.  
  2279. } // end Draw_Stars
  2280.  
  2281. ////////////////////////////////////////////////////////////////////////////////
  2282.  
  2283. void Erase_Stars(void)
  2284. {
  2285. // this function erases the stars
  2286.  
  2287. int index;
  2288.  
  2289. for (index=0; index<NUM_STARS; index++)
  2290.     {
  2291.  
  2292.     Plot_Pixel_Fast_DB(stars[index].x,stars[index].y,stars[index].back);
  2293.  
  2294.     } // end for index
  2295.  
  2296. } // end Erase_Stars
  2297.  
  2298. //////////////////////////////////////////////////////////////////////////////
  2299.  
  2300. void Erase_Missiles(void)
  2301. {
  2302.  
  2303. // this function indexes through all the missiles and if they are active
  2304. // erases them by replacing the background color that was under them
  2305.  
  2306. int index;
  2307.  
  2308. for (index=0; index<NUM_MISSILES; index++)
  2309.     {
  2310.  
  2311.     // is this missile active
  2312.  
  2313.     if (missiles[index].state == MISS_ALIVE)
  2314.        {
  2315.  
  2316.        Plot_Pixel_Fast_DB(missiles[index].x,missiles[index].y,missiles[index].back);
  2317.  
  2318.        } // end if alive
  2319.  
  2320.     } // end for index
  2321.  
  2322. } // end Erase_Missiles
  2323.  
  2324. /////////////////////////////////////////////////////////////////////////////
  2325.  
  2326. void Behind_Missiles(void)
  2327. {
  2328.  
  2329. // this function indexes through all the missiles and if they are active
  2330. // scans the background color that is behind them so it can be replaced later
  2331.  
  2332. int index;
  2333.  
  2334. for (index=0; index<NUM_MISSILES; index++)
  2335.     {
  2336.  
  2337.     // is this missile active
  2338.  
  2339.     if (missiles[index].state == MISS_ALIVE)
  2340.        {
  2341.  
  2342.        missiles[index].back = Get_Pixel_DB(missiles[index].x,missiles[index].y);
  2343.  
  2344.        } // end if alive
  2345.  
  2346.     } // end for index
  2347.  
  2348. } // end Behind_Missiles
  2349.  
  2350. /////////////////////////////////////////////////////////////////////////////
  2351.  
  2352. void Draw_Missiles(void)
  2353. {
  2354.  
  2355. // this function indexes through all the missiles and if they are active
  2356. // draws the missile as a bright white pixel on the screen
  2357.  
  2358. int index;
  2359.  
  2360. for (index=0; index<NUM_MISSILES; index++)
  2361.     {
  2362.  
  2363.     // is this missile active
  2364.  
  2365.     if (missiles[index].state == MISS_ALIVE)
  2366.        {
  2367.  
  2368.        Plot_Pixel_Fast_DB(missiles[index].x,missiles[index].y,missiles[index].color);
  2369.  
  2370.        } // end if alive
  2371.  
  2372.     } // end for index
  2373.  
  2374. } // end Draw_Missiles
  2375.  
  2376. /////////////////////////////////////////////////////////////////////////////
  2377.  
  2378. void Move_Missiles(void)
  2379. {
  2380.  
  2381. // this function moves the missiles and does all the collision detection
  2382.  
  2383. int index,     // used for loops
  2384.     index2,
  2385.     index_3,
  2386.     pixel_y,   // used during barrier collsion scan
  2387.     delta_x,   // used to help test for bouding box collisions
  2388.     delta_y,
  2389.     miss_x,   // position of missile
  2390.     miss_y,
  2391.     creature_hit=0; // flag to jump out of loop when a creature has been hit
  2392.  
  2393. unsigned char pixel; // pixel extracted from screen used to test for barrier
  2394.                      // collisions
  2395. mech_ptr worker;     // the current mech being processed
  2396.  
  2397.  
  2398. // loop thru all missiles and perform a lot of tests
  2399.  
  2400. for (index=0; index<NUM_MISSILES; index++)
  2401.     {
  2402.  
  2403.     // is missile active
  2404.  
  2405.     if (missiles[index].state == MISS_ALIVE)
  2406.        {
  2407.  
  2408.        // move the missile
  2409.  
  2410.        miss_x = (missiles[index].x += missiles[index].xv);
  2411.        miss_y = (missiles[index].y += missiles[index].yv);
  2412.  
  2413.       // test if it's hit the edge of the screen or a wall
  2414.  
  2415.       if ( (miss_x >= SCREEN_WIDTH) || (miss_x <= 0) ||
  2416.           (miss_y > (SCREEN_HEIGHT-16)) || ( miss_y <=0) )
  2417.          {
  2418.          missiles[index].state = MISS_DEAD;
  2419.          continue;
  2420.  
  2421.          } // end if off edge of screen
  2422.  
  2423.        // test for player->creature collisions
  2424.        else
  2425.        if (mother.state == MOTHER_ALIVE && missiles[index].tag==PLAYER_MISSILE)
  2426.           {
  2427.  
  2428.           delta_x = miss_x - mother.x;
  2429.           delta_y = miss_y - mother.y;
  2430.  
  2431.           // test the bounding box
  2432.  
  2433.           if ( (delta_x >= 0 && delta_x <=sprite_width) &&
  2434.                (delta_y >= 0 && delta_y <=sprite_height))
  2435.              {
  2436.  
  2437.              // kill missile
  2438.  
  2439.              missiles[index].state = MISS_DEAD;
  2440.  
  2441.              // kill mother
  2442.  
  2443.              mother.state = MOTHER_DEAD;
  2444.  
  2445.              // start explosion
  2446.  
  2447.              Start_Explosion(mother.x+10, mother.y+10,1);
  2448.  
  2449.              // give the player some points
  2450.  
  2451.              player_score+=500;
  2452.  
  2453.              // this missile is done so move to next missile
  2454.  
  2455.              continue;
  2456.  
  2457.              } // end if a hit
  2458.  
  2459.           } // end if mother alive
  2460.  
  2461.           // test if missiles hit a creature
  2462.  
  2463.           creature_hit = 0; // reset this flag
  2464.  
  2465.           // make sure missole is players
  2466.  
  2467.           if (missiles[index].tag==PLAYER_MISSILE)
  2468.              {
  2469.  
  2470.              // this missile is from player do test it against all mechs
  2471.  
  2472.              for (index_3=0; index_3<num_mechs && !creature_hit; index_3++)
  2473.                  {
  2474.  
  2475.                  // extract the working mech
  2476.  
  2477.                  worker=(mech_ptr)&mech_array[index_3];
  2478.  
  2479.  
  2480.                  // test if the mech is a live and it isn't energizing
  2481.  
  2482.                  if (worker->state_1==MECH_ALIVE && energize_state>1)
  2483.                     {
  2484.  
  2485.                     // compute deltas
  2486.  
  2487.                     delta_x = miss_x - worker->x;
  2488.                     delta_y = miss_y - worker->y;
  2489.  
  2490.  
  2491.                     // test for collision
  2492.  
  2493.                     if ( (delta_x >= 0 && delta_x <=sprite_width) &&
  2494.                          (delta_y >= 0 && delta_y <=sprite_height))
  2495.                        {
  2496.  
  2497.                        // kill missile
  2498.  
  2499.                        missiles[index].state = MISS_DEAD;
  2500.  
  2501.                        // kill mech
  2502.  
  2503.                        worker->state_1     = MECH_DYING;
  2504.                        worker->counter_1   = 0;
  2505.                        worker->threshold_1 = 8;
  2506.  
  2507.                        creature_hit=1;
  2508.  
  2509.                        Play_Sound(SOUND_EXPL3);
  2510.  
  2511.                        // start explosion
  2512.  
  2513.                        player_score+=50;
  2514.  
  2515.                        } // end if a hit
  2516.  
  2517.                     } // end if worth testing
  2518.  
  2519.                  } // end for index_3
  2520.  
  2521.              } // end if missile was from player
  2522.  
  2523.        // if there was a hit no need to go any further, next itteration
  2524.  
  2525.           if (creature_hit)
  2526.              continue;
  2527.  
  2528.        // test for creature->player collisions
  2529.  
  2530.        if (player.state == PLAYER_ALIVE && missiles[index].tag==ENEMY_MISSILE)
  2531.           {
  2532.  
  2533.           // compute deltas
  2534.  
  2535.           delta_x = miss_x - player.x;
  2536.           delta_y = miss_y - player.y;
  2537.  
  2538.           // test for collision
  2539.  
  2540.           if ( (delta_x >= 0 && delta_x <=sprite_width) &&
  2541.                (delta_y >= 0 && delta_y <=sprite_height))
  2542.              {
  2543.  
  2544.              // reset state of player to dying
  2545.  
  2546.              player.state = PLAYER_DYING;
  2547.  
  2548.              player.anim_clock = 0;
  2549.  
  2550.              // decrease number of ships
  2551.  
  2552.              player_ships--;
  2553.  
  2554.              // kill missile
  2555.  
  2556.              missiles[index].state = MISS_DEAD;
  2557.  
  2558.              // start the players death
  2559.  
  2560.              Start_PDeath();
  2561.  
  2562.              } // end if player hit
  2563.  
  2564.           } // end if player is alive to be hit
  2565.  
  2566.        // test for barrier collisions by scanning the pixels in the near vicinity
  2567.        // to the torpedo
  2568.  
  2569.        for (pixel_y=miss_y; pixel_y<miss_y+8; pixel_y++)
  2570.            {
  2571.  
  2572.            pixel=Get_Pixel_DB(miss_x, pixel_y);
  2573.  
  2574.            if (pixel>=BARRIER_START_COLOR && pixel<=BARRIER_END_COLOR)
  2575.               {
  2576.  
  2577.               // kill missile
  2578.  
  2579.               missiles[index].state = MISS_DEAD;
  2580.  
  2581.               // start explosion
  2582.  
  2583.               Start_Explosion(miss_x, pixel_y,1);
  2584.  
  2585.               // smash barrier a bit
  2586.  
  2587.               for (index2=0; index2<25; index2++)
  2588.                   {
  2589.  
  2590.                   Plot_Pixel_Fast_DB(miss_x-4+rand()%8, pixel_y-4+rand()%8, 0);
  2591.  
  2592.                   } // end for
  2593.  
  2594.               break;
  2595.  
  2596.               } // end if barrier hit
  2597.  
  2598.            } // end for pixel_y
  2599.  
  2600.        } // end if missile alive
  2601.  
  2602.     } // end for index
  2603.  
  2604. } // end Move_Missiles
  2605.  
  2606. /////////////////////////////////////////////////////////////////////////////
  2607.  
  2608. void Start_Missile(sprite_ptr who,
  2609.                    int x,
  2610.                    int y,
  2611.                    int xv,
  2612.                    int yv,
  2613.                    int color,
  2614.                    int tag)
  2615. {
  2616.  
  2617. // this function scans through the missile array and tries to find one that
  2618. // isn't being used.  this function could be more efficient.
  2619.  
  2620. int index;
  2621.  
  2622. // scan for a useable missle
  2623.  
  2624. for (index=0; index<NUM_MISSILES; index++)
  2625.     {
  2626.     // is this missile free?
  2627.  
  2628.     if (missiles[index].state == MISS_DEAD)
  2629.        {
  2630.  
  2631.        // set up fields
  2632.  
  2633.        missiles[index].state = MISS_ALIVE;
  2634.        missiles[index].x     = x;
  2635.        missiles[index].y     = y;
  2636.        missiles[index].xv    = xv;
  2637.        missiles[index].yv    = yv;
  2638.        missiles[index].color = color;
  2639.        missiles[index].back  = Get_Pixel_DB(x,y);
  2640.        missiles[index].tag   = tag;
  2641.  
  2642.        break; // exit loop
  2643.  
  2644.        } // end if found a good one
  2645.  
  2646.     } // end for index
  2647.  
  2648. } // end Start_Missile
  2649.  
  2650. /////////////////////////////////////////////////////////////////////////////
  2651.  
  2652. void Init_Missiles(void)
  2653. {
  2654. // this function just makes sure all the "state" fields of the missiles are
  2655. // dead so that we don't get any strays on start up.  Remember never assume
  2656. // that variables are zeroed on instantiation!
  2657.  
  2658. int index;
  2659.  
  2660. for (index=0; index<NUM_MISSILES; index++)
  2661.     missiles[index].state = MISS_DEAD;
  2662.  
  2663. } // Init_Missiles
  2664.  
  2665. ////////////////////////////////////////////////////////////////////////////
  2666.  
  2667. void Start_Explosion(int x,int y,int speed)
  2668. {
  2669. // this function stars a generic explosion
  2670. int index;
  2671.  
  2672. // scan for a useable explosion
  2673.  
  2674. for (index=0; index<NUM_EXPLOSIONS; index++)
  2675.     {
  2676.  
  2677.     if (explosions[index].state == EXPLOSION_DEAD)
  2678.        {
  2679.  
  2680.        // set up fields
  2681.  
  2682.        explosions[index].state      = EXPLOSION_ALIVE;
  2683.        explosions[index].x          = x-10;
  2684.        explosions[index].y          = y-10;
  2685.        explosions[index].curr_frame = 0;
  2686.        explosions[index].anim_speed = speed;
  2687.        explosions[index].anim_clock = 0;
  2688.  
  2689.        // scan background to be safe
  2690.  
  2691.        Behind_Sprite_DB((sprite_ptr)&explosions[index]);
  2692.  
  2693.        // make sound
  2694.  
  2695.        Play_Sound(SOUND_EXPL2);
  2696.  
  2697.        break; // exit loop
  2698.  
  2699.        } // end if found a good one
  2700.  
  2701.     } // end for index
  2702.  
  2703. } // end Start_Explosion
  2704.  
  2705. /////////////////////////////////////////////////////////////////////////////
  2706.  
  2707. void Behind_Explosions(void)
  2708. {
  2709.  
  2710. // this function scans under the explosions
  2711.  
  2712. int index;
  2713.  
  2714. // scan for a running explosions
  2715.  
  2716. for (index=0; index<NUM_EXPLOSIONS; index++)
  2717.     {
  2718.  
  2719.     if (explosions[index].state == EXPLOSION_ALIVE)
  2720.        {
  2721.        Behind_Sprite_DB((sprite_ptr)&explosions[index]);
  2722.  
  2723.        } // end if found a good one
  2724.  
  2725.     } // end for index
  2726.  
  2727. } // end Behind_Explosions
  2728.  
  2729. /////////////////////////////////////////////////////////////////////////////
  2730.  
  2731. void Erase_Explosions(void)
  2732. {
  2733. // this function erases all the current explosions
  2734. int index;
  2735.  
  2736. // scan for a useable explosion
  2737.  
  2738. for (index=0; index<NUM_EXPLOSIONS; index++)
  2739.     {
  2740.  
  2741.     if (explosions[index].state == EXPLOSION_ALIVE)
  2742.        {
  2743.        Erase_Sprite_DB((sprite_ptr)&explosions[index]);
  2744.  
  2745.        } // end if found a good one
  2746.  
  2747.     } // end for index
  2748.  
  2749. } // end Erase_Explosions
  2750.  
  2751. /////////////////////////////////////////////////////////////////////////////
  2752.  
  2753. void Draw_Explosions(void)
  2754. {
  2755. // this function draws the explosion
  2756.  
  2757. int index;
  2758.  
  2759. // scan for a useable explosion
  2760.  
  2761. for (index=0; index<NUM_EXPLOSIONS; index++)
  2762.     {
  2763.  
  2764.     // make sure this explosion is alive
  2765.  
  2766.     if (explosions[index].state == EXPLOSION_ALIVE)
  2767.        {
  2768.        Draw_Sprite_DB((sprite_ptr)&explosions[index]);
  2769.  
  2770.        } // end if found a good one
  2771.  
  2772.     } // end for index
  2773.  
  2774. } // end Draw_Explosions
  2775.  
  2776. /////////////////////////////////////////////////////////////////////////////
  2777.  
  2778. void Animate_Explosions(void)
  2779. {
  2780. // this function steps the explosion thru the frames of animation
  2781. int index;
  2782.  
  2783. // scan for a useable explosion
  2784.  
  2785. for (index=0; index<NUM_EXPLOSIONS; index++)
  2786.     {
  2787.     // test if explosion is alive
  2788.     if (explosions[index].state == EXPLOSION_ALIVE)
  2789.        {
  2790.        // test if it's time to change frames
  2791.  
  2792.        if (++explosions[index].anim_clock == explosions[index].anim_speed)
  2793.           {
  2794.           // is the explosion over?
  2795.  
  2796.           if (++explosions[index].curr_frame == 6)
  2797.              explosions[index].state = EXPLOSION_DEAD;
  2798.  
  2799.           // reset animation clock for future
  2800.  
  2801.           explosions[index].anim_clock = 0;
  2802.  
  2803.           } // end if time ti change frames
  2804.  
  2805.        } // end if found a good one
  2806.  
  2807.     } // end for index
  2808.  
  2809. } // end Animate_Explosions
  2810.  
  2811. //////////////////////////////////////////////////////////////////////////////
  2812.  
  2813. void Init_Explosions(void)
  2814. {
  2815. // reset all explosions
  2816.  
  2817. int index;
  2818.  
  2819. for (index=0; index<NUM_EXPLOSIONS; index++)
  2820.     explosions[index].state = EXPLOSION_DEAD;
  2821.  
  2822. } // Init_Explosions
  2823.  
  2824. ////////////////////////////////////////////////////////////////////////////
  2825.  
  2826. void Display_Instruments(void)
  2827. {
  2828. // this function draws all the information on the control panel
  2829.  
  2830. char buffer[128];
  2831.  
  2832. // show the ships
  2833.  
  2834. sprintf(buffer,"%ld ",player_ships);
  2835.  
  2836. Blit_String_DB(42,189,10,buffer,0);
  2837.  
  2838. // show the score
  2839.  
  2840. sprintf(buffer,"%ld",player_score);
  2841.  
  2842. Blit_String_DB(142,189,10,buffer,0);
  2843.  
  2844. // show the energy
  2845.  
  2846. if (player_energy>=0)
  2847.    {
  2848.    sprintf(buffer,"%ld ",player_energy);
  2849.    Blit_String_DB(276,189,10,buffer,0);
  2850.    }
  2851. else
  2852.    Blit_String_DB(276,189,12,"CHRG",0);
  2853.  
  2854. } // end Display_Instruments
  2855.  
  2856. ///////////////////////////////////////////////////////////////////////////
  2857.  
  2858. void Erase_Instruments(void)
  2859. {
  2860.  
  2861. // this function erases the instruments
  2862.  
  2863. Blit_String_DB(42,189,0," ",0);
  2864.  
  2865. Blit_String_DB(142,189,0,"      ",0);
  2866.  
  2867. Blit_String_DB(276,189,0,"    ",0);
  2868.  
  2869. } // end Erase_Instruments
  2870.  
  2871. ///////////////////////////////////////////////////////////////////////////
  2872.  
  2873. void Load_Background(void)
  2874. {
  2875. // this function loads in thre background imagery
  2876.  
  2877. // load in the background image into the double buffer
  2878.  
  2879. PCX_Init((pcx_picture_ptr)&background_pcx);
  2880.  
  2881. PCX_Load("mechback.pcx", (pcx_picture_ptr)&background_pcx,1);
  2882.  
  2883. // copy the background into the double buffer
  2884.  
  2885. _fmemcpy((char far *)double_buffer,
  2886.          (char far *)(background_pcx.buffer),
  2887.          SCREEN_WIDTH*SCREEN_HEIGHT);
  2888.  
  2889. PCX_Delete((pcx_picture_ptr)&background_pcx);
  2890.  
  2891. } // end Load_Background
  2892.  
  2893. ///////////////////////////////////////////////////////////////////////////
  2894.  
  2895. void Do_Intro(void)
  2896. {
  2897.  
  2898. // this function does the introduction and the instructions
  2899.  
  2900. // load intro screen and display for a few secs.
  2901.  
  2902. PCX_Init((pcx_picture_ptr)&intro_pcx);
  2903.  
  2904. PCX_Load("mechint.pcx", (pcx_picture_ptr)&intro_pcx,1);
  2905.  
  2906. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  2907.  
  2908. // let user see it
  2909.  
  2910. Delay(50);
  2911.  
  2912. Fade_Lights();
  2913.  
  2914. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  2915.  
  2916. // load instructions and wait for key press
  2917.  
  2918. PCX_Init((pcx_picture_ptr)&intro_pcx);
  2919.  
  2920. PCX_Load("mechins.pcx", (pcx_picture_ptr)&intro_pcx,1);
  2921.  
  2922. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  2923.  
  2924. // let user see it
  2925.  
  2926. getch();
  2927.  
  2928. Melt();
  2929.  
  2930. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  2931.  
  2932. } // end Do_Intro
  2933.  
  2934. ///////////////////////////////////////////////////////////////////////////
  2935.  
  2936. void Load_Player(void)
  2937. {
  2938.  
  2939. // this function loads in the imagery an initializes the mech
  2940.  
  2941.  
  2942. // load in imagery for player
  2943.  
  2944. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  2945.  
  2946. PCX_Load("mech.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  2947.  
  2948. // initialize player and extract birtmaps
  2949.  
  2950. sprite_width  = 18;
  2951. sprite_height = 18;
  2952.  
  2953. Sprite_Init((sprite_ptr)&player,0,0,0,0,0,0);
  2954.  
  2955. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&player,0,0,3);
  2956. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&player,1,1,3);
  2957. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&player,2,2,3);
  2958. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&player,3,3,3);
  2959. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&player,4,4,3);
  2960. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&player,5,5,3);
  2961.  
  2962. player.x          = 160;
  2963. player.y          = 168;
  2964. player.curr_frame = 0;
  2965. player.state      = PLAYER_ALIVE;
  2966.  
  2967.  
  2968. } // end Load_Player
  2969.  
  2970. ///////////////////////////////////////////////////////////////////////////
  2971.  
  2972. void Load_Mother(void)
  2973.  
  2974. {
  2975. // this function loads up the imagery for the mother ship
  2976. // load up mother ship
  2977.  
  2978. Sprite_Init((sprite_ptr)&mother,0,0,0,0,0,0);
  2979.  
  2980. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&mother,0,0,4);
  2981. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&mother,1,1,4);
  2982.  
  2983. mother.x          = 0;
  2984. mother.y          = 0;
  2985. mother.curr_frame = 0;
  2986. mother.state      = MOTHER_DEAD;
  2987.  
  2988.  
  2989. } // end Load_Mother
  2990.  
  2991. ///////////////////////////////////////////////////////////////////////////
  2992.  
  2993. void Load_Explosions(void)
  2994. {
  2995. // this function loads in the imagery for the explosions
  2996.  
  2997. int index;
  2998.  
  2999. // load data for explosions
  3000.  
  3001.  
  3002. // load in frames for fire
  3003.  
  3004. for (index=0; index<NUM_EXPLOSIONS; index++)
  3005.     {
  3006.  
  3007.     Sprite_Init((sprite_ptr)&explosions[index],0,0,0,0,0,0);
  3008.  
  3009.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3010.                     (sprite_ptr)&explosions[index],0,6,3);
  3011.  
  3012.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3013.                     (sprite_ptr)&explosions[index],1,7,3);
  3014.  
  3015.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3016.                     (sprite_ptr)&explosions[index],2,8,3);
  3017.  
  3018.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3019.                     (sprite_ptr)&explosions[index],3,9,3);
  3020.  
  3021.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3022.                     (sprite_ptr)&explosions[index],4,10,3);
  3023.  
  3024.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3025.                     (sprite_ptr)&explosions[index],5,11,3);
  3026.  
  3027.     } // end for
  3028.  
  3029. } // end Load_Explosions
  3030.  
  3031. ///////////////////////////////////////////////////////////////////////////
  3032.  
  3033. void Load_Mechs(void)
  3034. {
  3035. // this function loads the imagery for the mechs
  3036.  
  3037. int index;
  3038.  
  3039. // load in images for robots
  3040.  
  3041. // initialize the sprites used for mechs
  3042.  
  3043. Sprite_Init((sprite_ptr)&robot_1,0,0,0,0,0,0);
  3044. Sprite_Init((sprite_ptr)&robot_2,0,0,0,0,0,0);
  3045. Sprite_Init((sprite_ptr)&robot_3,0,0,0,0,0,0);
  3046.  
  3047. // zer these fields out for good measure
  3048.  
  3049. robot_1.x          = 0;
  3050. robot_1.y          = 0;
  3051. robot_1.curr_frame = 0;
  3052.  
  3053. robot_2.x          = 0;
  3054. robot_2.y          = 0;
  3055. robot_2.curr_frame = 0;
  3056.  
  3057. robot_3.x          = 0;
  3058. robot_3.y          = 0;
  3059. robot_3.curr_frame = 0;
  3060.  
  3061. // extract all the bitmaps out of pcx file
  3062.  
  3063. for (index=0; index<NUM_ROBOT_FRAMES; index++)
  3064.     {
  3065.  
  3066.  
  3067.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3068.                     (sprite_ptr)&robot_1,index,index,0);
  3069.  
  3070.  
  3071.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3072.                     (sprite_ptr)&robot_2,index,index,1);
  3073.  
  3074.  
  3075.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3076.                     (sprite_ptr)&robot_3,index,index,2);
  3077.  
  3078.  
  3079.     } // end for index
  3080.  
  3081. // delete imagery file
  3082.  
  3083. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3084.  
  3085.  
  3086. } // end Load_Mechs
  3087.  
  3088. ///////////////////////////////////////////////////////////////////////////
  3089.  
  3090. void main(int argc,char **argv)
  3091. {
  3092. // this is the main function
  3093.  
  3094. int done=0,       // exit flag for whole system
  3095.     fired=0,      // used to track if a player has fired a missile
  3096.     index;        // used for loop variable
  3097.  
  3098. char buffer[80];  // buffer to hold strings during printing
  3099.  
  3100. printf("\nStarting mechs...");
  3101.  
  3102. // initialize sound system
  3103.  
  3104. sound_available = Initialize_Sound_System();
  3105.  
  3106. Delay(100);
  3107.  
  3108. // set video mode to 320x200 256 color mode
  3109.  
  3110. Set_Video_Mode(VGA256);
  3111.  
  3112. // create a double buffer
  3113.  
  3114. if (!Create_Double_Buffer(SCREEN_HEIGHT))
  3115.    {
  3116.    printf("\nNot enough memory to create double buffer.");
  3117.  
  3118.    } // end if
  3119.  
  3120. // create cosine look up table
  3121.  
  3122. for (index=0; index<320; index++)
  3123.     cos_look[index] = (int)(8*cos(3.14159*5*(float)index/180));
  3124.  
  3125. // clear the double buffer
  3126.  
  3127. Fill_Double_Buffer(0);
  3128.  
  3129. // load the background imagery
  3130.  
  3131. Load_Background();
  3132.  
  3133. // do the introduction
  3134.  
  3135. Do_Intro();
  3136.  
  3137. // install our ISR
  3138.  
  3139. Old_Isr = _dos_getvect(KEYBOARD_INT);
  3140.  
  3141. _dos_setvect(KEYBOARD_INT, New_Key_Int);
  3142.  
  3143. // load the player
  3144.  
  3145. Load_Player();
  3146.  
  3147. // load the mechs
  3148.  
  3149. Load_Mother();
  3150.  
  3151. // load the explosions
  3152.  
  3153. Load_Explosions();
  3154.  
  3155. // load the mechs
  3156.  
  3157. Load_Mechs();
  3158.  
  3159. // set up the current wave
  3160.  
  3161. waves[0]  = wave_0;
  3162. waves[1]  = wave_1;
  3163. waves[2]  = wave_2;
  3164. waves[3]  = wave_3;
  3165. waves[4]  = wave_4;
  3166. waves[5]  = wave_5;
  3167. waves[6]  = wave_6;
  3168. waves[7]  = wave_7;
  3169. waves[8]  = wave_8;
  3170. waves[9]  = wave_9;
  3171. waves[10] = wave_10;
  3172. waves[11] = wave_11;
  3173. waves[12] = wave_12;
  3174. waves[13] = wave_13;
  3175. waves[14] = wave_14;
  3176.  
  3177. current_wave = waves[wave_number];
  3178.  
  3179. // initialize all mechs
  3180.  
  3181. Init_Mechs();
  3182.  
  3183. // initialize starfield
  3184.  
  3185. Init_Stars();
  3186.  
  3187. // initialize the explosions
  3188.  
  3189. Init_Explosions();
  3190.  
  3191. // start the level off
  3192.  
  3193. Start_Wave();
  3194.  
  3195. // scan under mechs
  3196.  
  3197. Behind_Mechs();
  3198.  
  3199. // scan the background under player
  3200.  
  3201. Behind_Sprite_DB((sprite_ptr)&player);
  3202.  
  3203. // scan under the stars
  3204.  
  3205. Behind_Stars();
  3206.  
  3207. // display instruments for first time
  3208.  
  3209. Display_Instruments();
  3210.  
  3211. // main event loop
  3212.  
  3213. while(!done)
  3214.      {
  3215.  
  3216.      // reset all event variables
  3217.  
  3218.      fired = 0 ;
  3219.  
  3220.      // erase all objects
  3221.  
  3222.      Erase_Sprite_DB((sprite_ptr)&player);
  3223.  
  3224.      Erase_Missiles();
  3225.  
  3226.      Erase_Stars();
  3227.  
  3228.      Erase_Mother();
  3229.  
  3230.      Erase_Mechs();
  3231.  
  3232.      Erase_PDeath();
  3233.  
  3234.      Erase_Explosions();
  3235.  
  3236.      Erase_Instruments();
  3237.  
  3238.      // move all objects and trasnform
  3239.  
  3240.      if (player.state==PLAYER_ALIVE)
  3241.         {
  3242.  
  3243.         // wait key was pressed
  3244.  
  3245.         if (key_table[INDEX_RIGHT])
  3246.            {
  3247.            player.x+=PLAYER_X_MOVE;
  3248.  
  3249.            if (player.x > SCREEN_WIDTH-20)
  3250.                player.x = SCREEN_WIDTH-20;
  3251.  
  3252.            } // end if right
  3253.  
  3254.         else
  3255.         if (key_table[INDEX_LEFT])
  3256.            {
  3257.  
  3258.            player.x-=PLAYER_X_MOVE;
  3259.  
  3260.            if (player.x < 0)
  3261.               player.x = 0;
  3262.  
  3263.            } // end if  left
  3264.  
  3265.  
  3266.         if (key_table[INDEX_Q])
  3267.            {
  3268.            done=1;
  3269.  
  3270.            } // end if q
  3271.  
  3272.  
  3273.         if (key_table[INDEX_SPACE])
  3274.            {
  3275.            if (player_gun_state == PLAYER_NOT_FIRING && player_energy>0)
  3276.               {
  3277.  
  3278.               player_gun_state = PLAYER_FIRING;
  3279.               fired = 1;
  3280.  
  3281.               player_energy -= (5+rand()%2);
  3282.  
  3283.               if (player_energy < -100)
  3284.                  player_energy=-100;
  3285.  
  3286.               } // end if not currently firing
  3287.  
  3288.            } // end if space
  3289.  
  3290.         } // end if player alive
  3291.  
  3292.      // move missiles
  3293.  
  3294.      Move_Missiles();
  3295.  
  3296.      Move_Mother();
  3297.  
  3298.      Move_Stars();
  3299.  
  3300.      Move_Mechs();
  3301.  
  3302.      Animate_PDeath();
  3303.  
  3304.      Animate_Explosions();
  3305.  
  3306.      // critical area
  3307.  
  3308.      // do cannon retraction if player has fired
  3309.  
  3310.      if (fired)
  3311.         {
  3312.         Start_Missile((sprite_ptr)&player,
  3313.                       player.x+2,
  3314.                       player.y+4,
  3315.                       0,
  3316.                       -8,
  3317.                       12,
  3318.                       PLAYER_MISSILE);
  3319.  
  3320.         Start_Missile((sprite_ptr)&player,
  3321.                       player.x+15,
  3322.                       player.y+4,
  3323.                       0,
  3324.                       -8,
  3325.                       12,
  3326.                       PLAYER_MISSILE);
  3327.  
  3328.         Play_Sound(SOUND_MISSILE);
  3329.  
  3330.         } // end if fired
  3331.  
  3332.      // do mother ship
  3333.  
  3334.      Control_Mother();
  3335.  
  3336.      // start new wave here
  3337.  
  3338.      if (mechs_killed==num_mechs)
  3339.         {
  3340.         // next wave
  3341.  
  3342.         wave_number++;
  3343.  
  3344.         Start_Wave();
  3345.  
  3346.         // reset mech counter
  3347.  
  3348.         mechs_killed=0;
  3349.  
  3350.         } // end if start next wave
  3351.  
  3352.      // scan background
  3353.  
  3354.      Behind_Sprite_DB((sprite_ptr)&player);
  3355.  
  3356.      Behind_Missiles();
  3357.  
  3358.      Behind_Mother();
  3359.  
  3360.      Behind_Mechs();
  3361.  
  3362.      Behind_Stars();
  3363.  
  3364.      Behind_Explosions();
  3365.  
  3366.      Behind_PDeath();
  3367.  
  3368.      // draw objects
  3369.  
  3370.      // flicker engine
  3371.  
  3372.      if (player.state==PLAYER_ALIVE)
  3373.      {
  3374.      if (player_gun_state==PLAYER_NOT_FIRING)
  3375.         {
  3376.  
  3377.         player.curr_frame = rand()%2;
  3378.  
  3379.         if (++player_energy > 100) player_energy = 100;
  3380.  
  3381.  
  3382.         } // end if not firing
  3383.      else
  3384.         {
  3385.         if (++player.curr_frame > 4)
  3386.            {
  3387.            player.curr_frame = 0;
  3388.            player_gun_state = PLAYER_NOT_FIRING;
  3389.            } // end if done retracting
  3390.  
  3391.         } // end else player is firing so retract
  3392.  
  3393.      } // end if player alive
  3394.    else
  3395.       player.curr_frame = 5;
  3396.  
  3397.      // draw everything
  3398.  
  3399.      Draw_Sprite_DB((sprite_ptr)&player);
  3400.  
  3401.      Draw_Missiles();
  3402.  
  3403.      Draw_Stars();
  3404.  
  3405.      Draw_Explosions();
  3406.  
  3407.      Draw_Mother();
  3408.  
  3409.      Draw_Mechs();
  3410.  
  3411.      Draw_PDeath();
  3412.  
  3413.      Display_Instruments();
  3414.  
  3415.      Blink_Lights();
  3416.  
  3417.      // place double buffer
  3418.  
  3419.      Show_Double_Buffer(double_buffer);
  3420.  
  3421.      // test if player is dead
  3422.  
  3423.      if (player_ships==0 && player.anim_clock >= PLAYER_DEATH_TIME)
  3424.         {
  3425.  
  3426.         sprintf(buffer,"G A M E  O V E R");
  3427.  
  3428.         Blit_String_G(160-64,60,4,buffer,1);
  3429.  
  3430.         sprintf(buffer,"Final Score %ld",player_score);
  3431.  
  3432.         Blit_String_G(160-64,80,1,buffer,1);
  3433.  
  3434.         done=1;
  3435.  
  3436.         } // end if player done
  3437.  
  3438.      // display header for level number
  3439.  
  3440.      else
  3441.      {
  3442.      if (energize_state==1)
  3443.         {
  3444.  
  3445.         sprintf(buffer,"W A V E  %d",wave_number+1);
  3446.  
  3447.         Blit_String_G(160-40,60,10,buffer,1);
  3448.  
  3449.         } // end if need to display level
  3450.      else
  3451.      if (energize_state==2)
  3452.         {
  3453.  
  3454.         // erase words
  3455.  
  3456.         Blit_String_G(160-40,60,0,"             ",0);
  3457.  
  3458.         // move on to sequence over
  3459.  
  3460.         energize_state++;
  3461.  
  3462.         } // end if energize over
  3463.  
  3464.      } // end else ok to put up wave
  3465.  
  3466.      // wait a second
  3467.  
  3468.      // test if this is a really fast machine and either
  3469.      // wait 1/70 of a sec or 1/8 of second
  3470.  
  3471.      if (argc > 1)
  3472.         Delay(1);
  3473.      else
  3474.         Wait_For_Vsync();
  3475.  
  3476.      // update all global counters and timers
  3477.  
  3478.      game_clock++;
  3479.  
  3480.      } // end while
  3481.  
  3482. // play latter sound
  3483.  
  3484. Play_Sound(SOUND_END);
  3485.  
  3486. Delay(100);
  3487.  
  3488. // use one of screen fx as exit
  3489.  
  3490. Fade_Lights();
  3491.  
  3492. // reset the video mode back to text
  3493.  
  3494. Set_Video_Mode(TEXT_MODE);
  3495.  
  3496. // delete all the mech data
  3497.  
  3498. Delete_Mechs();
  3499.  
  3500. // free the double buffer
  3501.  
  3502. Delete_Double_Buffer();
  3503.  
  3504. // replace old ISR
  3505.  
  3506. _dos_setvect(KEYBOARD_INT, Old_Isr);
  3507.  
  3508. // close sound system
  3509.  
  3510. Close_Sound_System();
  3511.  
  3512. // get the hell out of here!!!!!
  3513.  
  3514. } // end main
  3515.  
  3516.  
  3517.