home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_18 / krkm1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-27  |  90.5 KB  |  3,434 lines

  1.  
  2. // KRK.C - Version 1.0, Andre' LaMothe
  3.  
  4. // I N C L U D E S ///////////////////////////////////////////////////////////
  5.  
  6. #include <io.h>
  7. #include <conio.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <dos.h>
  11. #include <bios.h>
  12. #include <fcntl.h>
  13. #include <memory.h>
  14. #include <malloc.h>
  15. #include <math.h>
  16. #include <string.h>
  17.  
  18. // include all of our stuff
  19.  
  20. #include "black3.h"
  21. #include "black4.h"
  22. #include "black5.h"
  23. #include "black6.h"
  24. #include "black8.h"
  25. #include "black9.h"
  26.  
  27. #include "black18.h"    // the newest version of the 3-D library
  28. #include "krkm0.h"
  29.  
  30. ///////////////////////////////////////////////////////////////////////////////
  31.  
  32. void Select_Mech(void)
  33. {
  34. // this function allows the user to select a ship via the keyboard
  35. // the function draw the ship in wire frame, displays the specifications
  36. // of the ship and then allows the user to select or escape
  37.  
  38. int done=0,               // event loop exit flag
  39.     current_ship_type,    // current displayed ship
  40.     index;                // looping variable
  41.  
  42. // set current ship to the actual one player is using
  43.  
  44. current_ship_type = players_ship_type;
  45.  
  46. // clear the screen
  47.  
  48. Fill_Screen(0);
  49.  
  50. // make sure user isn't hitting the enter key still
  51.  
  52. while(keys_active);
  53.  
  54. // enter into main event loop
  55.  
  56. while(!done)
  57.      {
  58.      // clear the double buffer
  59.  
  60.      Fill_Double_Buffer_32(0);
  61.  
  62.      // get user input
  63.  
  64.      if (keys_active)
  65.         {
  66.  
  67.         // test for various inputs
  68.  
  69.         if (keyboard_state[MAKE_RIGHT])
  70.            {
  71.            // move to next ship
  72.  
  73.            // click the next button
  74.  
  75.            if (++current_ship_type==2)
  76.               current_ship_type=0;
  77.  
  78.            // make a key sound
  79.  
  80.            Digital_FX_Play(KRKKEY_VOC,3);
  81.  
  82.            } // end if
  83.         else
  84.         if (keyboard_state[MAKE_LEFT])
  85.            {
  86.            // move to previous ship
  87.  
  88.            // click the previous button
  89.  
  90.            if (--current_ship_type<0)
  91.               current_ship_type=1;
  92.  
  93.            // make a key sound
  94.  
  95.            Digital_FX_Play(KRKKEY_VOC,3);
  96.  
  97.            } // end if
  98.         else
  99.         if (keyboard_state[MAKE_ENTER])
  100.            {
  101.            // select the current ship
  102.  
  103.            // make players ship the selected ship
  104.  
  105.            players_ship_type = current_ship_type;
  106.  
  107.            // exit
  108.  
  109.            done = 1;
  110.  
  111.            // make a key sound
  112.  
  113.            Digital_FX_Play(KRKKEY_VOC,3);
  114.  
  115.            } // end if
  116.         else
  117.         if (keyboard_state[MAKE_ESC])
  118.            {
  119.            // exit this menu and go back to main menu
  120.  
  121.            // exit
  122.  
  123.            done = 1;
  124.  
  125.            // make a key sound
  126.  
  127.            Digital_FX_Play(KRKKEY_VOC,3);
  128.  
  129.            } // end if
  130.  
  131.         } // end if keys active
  132.  
  133.      // draw the object and it's stats
  134.  
  135.      if (current_ship_type==PLAYER_TALLON)
  136.         {
  137.         // change heading of tallon model
  138.  
  139.         if ((dynamic_obj[TALLONS_TEMPLATE].state+=5)>360)
  140.             dynamic_obj[TALLONS_TEMPLATE].state-=360;
  141.  
  142.         // perform the rotation
  143.  
  144.         Rotate_Object(&dynamic_obj[TALLONS_TEMPLATE],0,5,0);
  145.  
  146.         // update object template with new heading
  147.  
  148.         // set world position to a reasonable spot
  149.  
  150.         dynamic_obj[TALLONS_TEMPLATE].world_pos.x = -50;
  151.         dynamic_obj[TALLONS_TEMPLATE].world_pos.y = 0;
  152.         dynamic_obj[TALLONS_TEMPLATE].world_pos.z = 400;
  153.  
  154.         // convert object local coordinates to world coordinates
  155.  
  156.         Local_To_World_Object(&dynamic_obj[TALLONS_TEMPLATE]);
  157.  
  158.         // draw the object in wireframe
  159.  
  160.         Draw_Object_Wire(&dynamic_obj[TALLONS_TEMPLATE],12);
  161.  
  162.         // draw the stats
  163.  
  164.         Font_Engine_1(0,130,0,12,"TALLON SPECIFICATIONS",video_buffer);
  165.  
  166.         // draw the specfication strings
  167.  
  168.         for (index=0; index<NUM_SHIP_SPECS; index++)
  169.             Font_Engine_1(4,140+8*index,0,12,tallon_specs[index],video_buffer);
  170.  
  171.         } // end
  172.      else
  173.         {
  174.         // else must be a slider
  175.  
  176.         // change heading of slider model
  177.  
  178.         if ((dynamic_obj[SLIDERS_TEMPLATE].state+=5)>360)
  179.             dynamic_obj[SLIDERS_TEMPLATE].state-=360;
  180.  
  181.         // perform the rotation
  182.  
  183.         Rotate_Object(&dynamic_obj[SLIDERS_TEMPLATE],0,5,0);
  184.  
  185.         // set world position to a reasonable spot
  186.  
  187.         dynamic_obj[SLIDERS_TEMPLATE].world_pos.x = -50;
  188.         dynamic_obj[SLIDERS_TEMPLATE].world_pos.y = 0;
  189.         dynamic_obj[SLIDERS_TEMPLATE].world_pos.z = 400;
  190.  
  191.         // convert object local coordinates to world coordinates
  192.  
  193.         Local_To_World_Object(&dynamic_obj[SLIDERS_TEMPLATE]);
  194.  
  195.         // draw the object in wireframe
  196.  
  197.         Draw_Object_Wire(&dynamic_obj[SLIDERS_TEMPLATE],12);
  198.  
  199.         // draw the stats
  200.  
  201.         Font_Engine_1(0,130,0,12,"SLIDER SPECIFICATIONS",video_buffer);
  202.  
  203.         // draw the specfication strings
  204.  
  205.         for (index=0; index<NUM_SHIP_SPECS; index++)
  206.             Font_Engine_1(4,140+8*index,0,12,slider_specs[index],video_buffer);
  207.  
  208.         } // end else
  209.  
  210.      // draw the buttons
  211.  
  212.      buttons_spr.x          = 260;
  213.      buttons_spr.y          = 20;
  214.      buttons_spr.curr_frame = 4;
  215.  
  216.      Sprite_Draw((sprite_ptr)&buttons_spr,double_buffer,0);
  217.  
  218.      buttons_spr.y          = 40;
  219.      buttons_spr.curr_frame = 6;
  220.  
  221.      Sprite_Draw((sprite_ptr)&buttons_spr,double_buffer,0);
  222.  
  223.      buttons_spr.y          = 60;
  224.      buttons_spr.curr_frame = 2;
  225.  
  226.      Sprite_Draw((sprite_ptr)&buttons_spr,double_buffer,0);
  227.  
  228.      buttons_spr.y          = 80;
  229.      buttons_spr.curr_frame = 0;
  230.  
  231.      Sprite_Draw((sprite_ptr)&buttons_spr,double_buffer,0);
  232.  
  233.      // draw the headers
  234.  
  235.      Font_Engine_1(60,0,0,12,"KILL OR BE KILLED BATTLE MECH SELECTION",double_buffer);
  236.  
  237.      // display double buffer
  238.  
  239.      Display_Double_Buffer_32(double_buffer,0);
  240.  
  241.      // slow things down a bit
  242.  
  243.      Time_Delay(1);
  244.  
  245.      // check on music
  246.  
  247.      if (music_enabled)
  248.         {
  249.         // test if piece is complete or has been stopped
  250.  
  251.         if (Music_Status()==2 || Music_Status()==0)
  252.            {
  253.            // advance to next sequence
  254.  
  255.            if (++intro_seq_index==14)
  256.               intro_seq_index=0;
  257.  
  258.            Music_Play((music_ptr)&song,intro_sequence[intro_seq_index]);
  259.  
  260.            } // end if
  261.  
  262.         } // end if music enabled
  263.  
  264.      } // end while
  265.  
  266. } // end Select_Mech
  267.  
  268. /////////////////////////////////////////////////////////////////////////////
  269.  
  270. void Misc_Color_Init(void)
  271. {
  272. // this function initializes various color registers for the game phase of
  273. // KRK
  274.  
  275. Write_Color_Reg(SHIELDS_REG,                  (RGB_color_ptr)&dark_blue);
  276. Write_Color_Reg(RADAR_REG,                    (RGB_color_ptr)&dark_blue);
  277. Write_Color_Reg(COMM_REG,                     (RGB_color_ptr)&dark_blue);
  278. Write_Color_Reg(HUD_REG,                      (RGB_color_ptr)&dark_blue);
  279. Write_Color_Reg(STS_REG,                      (RGB_color_ptr)&dark_green);
  280. Write_Color_Reg(HULL_REG,                     (RGB_color_ptr)&dark_green);
  281. Write_Color_Reg(OFF_REG,                      (RGB_color_ptr)&bright_green);
  282. Write_Color_Reg(PLAYERS_WEAPON_FIRE_REG,      (RGB_color_ptr)&black);
  283. Write_Color_Reg(ENGINES_TALLON_REG,           (RGB_color_ptr)&black);
  284. Write_Color_Reg(ENGINES_SLIDER_REG,           (RGB_color_ptr)&black);
  285. Write_Color_Reg(BARRIERS_REG,                 (RGB_color_ptr)&black);
  286. Write_Color_Reg(SHIELDS_FLICKER_REG,           (RGB_color_ptr)&black);
  287.  
  288. } // end Misc_Color_Init
  289.  
  290. ////////////////////////////////////////////////////////////////////////////
  291.  
  292. void Tallon_Color_FX(void)
  293. {
  294. // this function flickers the tallons engines
  295.  
  296. static int engine_counter=0; // used to track time from call to call
  297.  
  298. // test if it's time to change color
  299.  
  300. if (++engine_counter==1)
  301.    Write_Color_Reg(ENGINES_TALLON_REG,(RGB_color_ptr)&bright_blue);
  302. else
  303. if (engine_counter==2)
  304.    Write_Color_Reg(ENGINES_TALLON_REG,(RGB_color_ptr)&medium_blue);
  305. else
  306. if (engine_counter==3)
  307.    engine_counter=0;
  308.  
  309.  
  310. } // end Tallon_Color_FX
  311.  
  312. /////////////////////////////////////////////////////////////////////////////
  313.  
  314. void Slider_Color_FX(void)
  315. {
  316. // this function flickers the sliders engines
  317.  
  318. static int engine_counter=0; // used to track time from call to call
  319.  
  320. // test if it's time to change color
  321.  
  322. if (++engine_counter==1)
  323.    Write_Color_Reg(ENGINES_SLIDER_REG,(RGB_color_ptr)&bright_green);
  324. else
  325. if (engine_counter==2)
  326.    Write_Color_Reg(ENGINES_SLIDER_REG,(RGB_color_ptr)&medium_green);
  327. else
  328. if (engine_counter==3)
  329.    engine_counter=0;
  330.  
  331. } // end Slider_Color_FX
  332.  
  333. /////////////////////////////////////////////////////////////////////////////
  334.  
  335. void Barrier_Color_FX(void)
  336. {
  337. // this function flickers the game grid barriers beacon
  338.  
  339. static int beacon_counter=0; // used to track time from call to call
  340.  
  341. // test if it's time to change color
  342.  
  343. if (++beacon_counter==1)
  344.    Write_Color_Reg(BARRIERS_REG,(RGB_color_ptr)&bright_green);
  345. else
  346. if (beacon_counter==10)
  347.    Write_Color_Reg(BARRIERS_REG,(RGB_color_ptr)&dark_green);
  348. else
  349. if (beacon_counter==25)
  350.    beacon_counter=0;
  351.  
  352. } // end Barrier_Color_FX
  353.  
  354. /////////////////////////////////////////////////////////////////////////////
  355.  
  356. void Draw_Hud(void)
  357. {
  358. // this function draws the heads up display
  359.  
  360. char buffer[64]; // local working buffer
  361.  
  362. // create the string with the x,y,z and heading in it
  363.  
  364. sprintf(buffer,"X(%5d) Y(%5d) Z(%5d) TRAJ(%4d) KILLS:(%3d)",(int)view_point.x,
  365.                                                             (int)view_point.y,
  366.                                                             (int)view_point.z,
  367.                                                             (int)ship_yaw,
  368.                                                             (int)ship_kills);
  369. // print the string to the double buffer
  370.  
  371. Font_Engine_1(16,10,0,12,buffer,double_buffer);
  372.  
  373. } // end Draw_Hud
  374.  
  375. /////////////////////////////////////////////////////////////////////////////
  376.  
  377. void Draw_Tactical(int command)
  378. {
  379. // this function is responsible for both draw the static tactical displays
  380. // and updating the currently active tactical display
  381.  
  382. int index,    // looping variable
  383.     color,    // holds a temp color
  384.     length;   // used to hold length of indicator bars
  385.  
  386. // test command and see what caller wants done
  387.  
  388. switch(command)
  389.       {
  390.  
  391.       case TACTICAL_CLEAR:
  392.            {
  393.            // totally clear the tactical display
  394.  
  395.            Draw_Rectangle(TACTICAL_X,
  396.                           TACTICAL_Y,
  397.                           TACTICAL_X+TACTICAL_WIDTH-1,
  398.                           TACTICAL_Y+TACTICAL_HEIGHT-1,
  399.                           0);
  400.  
  401.  
  402.            } break;
  403.  
  404.       case TACTICAL_DRAW:
  405.            {
  406.            // based on tactical to be displayed render static portion
  407.            // of it
  408.  
  409.            if (tactical_state==TACTICAL_MODE_STS)
  410.               {
  411.               tactical_spr.curr_frame = 2;
  412.  
  413.               // update button illuminations
  414.  
  415.               Write_Color_Reg(STS_REG, (RGB_color_ptr)&bright_green);
  416.               Write_Color_Reg(HULL_REG,(RGB_color_ptr)&dark_green);
  417.               Write_Color_Reg(OFF_REG, (RGB_color_ptr)&dark_green);
  418.  
  419.               } // end if
  420.  
  421.            else
  422.            if (tactical_state==TACTICAL_MODE_HULL)
  423.               {
  424.               // which hull should be displayed
  425.  
  426.               if (players_ship_type==PLAYER_TALLON)
  427.                  tactical_spr.curr_frame = 3;
  428.               else
  429.                  tactical_spr.curr_frame = 4;
  430.  
  431.               // update button illuminations
  432.  
  433.               Write_Color_Reg(STS_REG, (RGB_color_ptr)&dark_green);
  434.               Write_Color_Reg(HULL_REG,(RGB_color_ptr)&bright_green);
  435.               Write_Color_Reg(OFF_REG, (RGB_color_ptr)&dark_green);
  436.  
  437.  
  438.               } // end if
  439.            else
  440.               {
  441.               tactical_spr.curr_frame = 1;
  442.  
  443.               // update button illuminations
  444.  
  445.               Write_Color_Reg(STS_REG, (RGB_color_ptr)&dark_green);
  446.               Write_Color_Reg(HULL_REG,(RGB_color_ptr)&dark_green);
  447.               Write_Color_Reg(OFF_REG, (RGB_color_ptr)&bright_green);
  448.  
  449.               } // end else
  450.  
  451.            // now draw display
  452.  
  453.            tactical_spr.x = TACTICAL_X + 8;
  454.            tactical_spr.y = TACTICAL_Y + 6;
  455.  
  456.            Sprite_Draw((sprite_ptr)&tactical_spr, video_buffer,0);
  457.  
  458.            } break;
  459.  
  460.       case TACTICAL_UPDATE:
  461.            {
  462.            // based on tactical state update display accordingly
  463.  
  464.            switch(tactical_state)
  465.                  {
  466.  
  467.                  case TACTICAL_MODE_STS:
  468.                       {
  469.  
  470.                       // draw velocity gauge
  471.  
  472.                       length = (ship_speed<<1)/5;
  473.  
  474.                       // test for negative values
  475.  
  476.                       if (length<0)
  477.                          {
  478.                          // invert value
  479.  
  480.                          length = -length;
  481.  
  482.                          // show negative velocity with red
  483.  
  484.                          color = 32;
  485.  
  486.                          } // end if
  487.                       else
  488.                          {
  489.                          // show positive velocity with red
  490.  
  491.                          color = 144;
  492.  
  493.                          } // end else
  494.  
  495.                       // do a little out of bounds check
  496.  
  497.                       if (length>20)
  498.                          length = 20;
  499.  
  500.                       // draw visible portion of digital indicator
  501.  
  502.                       if (length>0)
  503.                          {
  504.  
  505.                          Line_H(TACTICAL_X+8+16,
  506.                                 TACTICAL_X+8+16+length,
  507.                                 TACTICAL_Y+6+5,
  508.                                 color);
  509.  
  510.                          Line_H(TACTICAL_X+8+16,
  511.                                 TACTICAL_X+8+16+length,
  512.                                 TACTICAL_Y+6+5+1,
  513.                                 color);
  514.                          }
  515.  
  516.                       // undraw old line (if any)
  517.  
  518.                       if (++length<=20)
  519.                          {
  520.                          // erase old line
  521.  
  522.                          Line_H(TACTICAL_X+8+16+length,
  523.                                 TACTICAL_X+8+16+20,
  524.                                 TACTICAL_Y+6+5,
  525.                                 0);
  526.  
  527.                          Line_H(TACTICAL_X+8+16+length,
  528.                                 TACTICAL_X+8+16+20,
  529.                                 TACTICAL_Y+6+5+1,
  530.                                0);
  531.  
  532.                          } // end if erase needed
  533.  
  534.                       // draw damage gauge
  535.  
  536.                       length = (ship_damage<<1)/5;
  537.  
  538.                       // check for negative values
  539.  
  540.                       if (length<0)
  541.                          length = -length;
  542.  
  543.                       // draw visible portion of digital indicator
  544.  
  545.                       if (length>0)
  546.                          {
  547.  
  548.                          Line_H(TACTICAL_X+8+16,
  549.                                 TACTICAL_X+8+16+length,
  550.                                 TACTICAL_Y+6+5+8,
  551.                                 96);
  552.  
  553.                          Line_H(TACTICAL_X+8+16,
  554.                                 TACTICAL_X+8+16+length,
  555.                                 TACTICAL_Y+6+5+8+1,
  556.                                 96);
  557.  
  558.                          } // end if
  559.  
  560.                       if (++length<=20)
  561.                          {
  562.                          // erase old line
  563.  
  564.                          Line_H(TACTICAL_X+8+16+length,
  565.                                 TACTICAL_X+8+16+20,
  566.                                 TACTICAL_Y+6+5+8,
  567.                                 0);
  568.  
  569.                          Line_H(TACTICAL_X+8+16+length,
  570.                                 TACTICAL_X+8+16+20,
  571.                                 TACTICAL_Y+6+5+8+1,
  572.                                0);
  573.  
  574.                          } // end if erase needed
  575.  
  576.                       // draw energy gauge
  577.  
  578.                       length = (ship_energy<<1)/5;
  579.  
  580.                       // check for negative values
  581.  
  582.                       if (length<0)
  583.                          length = -length;
  584.  
  585.                       // draw visible portion of digital indicator
  586.  
  587.                       if (length>0)
  588.                          {
  589.  
  590.                          Line_H(TACTICAL_X+8+16,
  591.                                 TACTICAL_X+8+16+length,
  592.                                 TACTICAL_Y+6+5+16,
  593.                                 96);
  594.  
  595.                          Line_H(TACTICAL_X+8+16,
  596.                                 TACTICAL_X+8+16+length,
  597.                                 TACTICAL_Y+6+5+16+1,
  598.                                 96);
  599.                          }
  600.  
  601.                       // undraw remainder of gauge
  602.  
  603.                       if (++length<=20)
  604.                          {
  605.                          // erase old line
  606.  
  607.                          Line_H(TACTICAL_X+8+16+length,
  608.                                 TACTICAL_X+8+16+20,
  609.                                 TACTICAL_Y+6+5+16,
  610.                                 0);
  611.  
  612.                          Line_H(TACTICAL_X+8+16+length,
  613.                                 TACTICAL_X+8+16+20,
  614.                                 TACTICAL_Y+6+5+16+1,
  615.                                0);
  616.  
  617.                          } // end if erase needed
  618.  
  619.                       } break;
  620.  
  621.                  case TACTICAL_MODE_HULL:
  622.                       {
  623.                       // do nothing for now
  624.  
  625.                       } break;
  626.  
  627.                  case TACTICAL_MODE_OFF:
  628.                       {
  629.                       // do nothing for now
  630.  
  631.                       } break;
  632.  
  633.                  default:break;
  634.  
  635.                  } // end switch
  636.  
  637.            } break;
  638.  
  639.       default:break;
  640.  
  641.       } // end switch
  642.  
  643. } // end Draw_Tactical
  644.  
  645. /////////////////////////////////////////////////////////////////////////////
  646.  
  647. void Load_Tactical(void)
  648. {
  649. // this function loads various icons for the tactical displays
  650.  
  651. int index; // looping variable
  652.  
  653. // load the imagery for the icons for display
  654.  
  655. PCX_Init((pcx_picture_ptr)&image_pcx);
  656. PCX_Load("krkdis.pcx", (pcx_picture_ptr)&image_pcx,1);
  657.  
  658. // intialize the tactical sprite
  659.  
  660. Sprite_Init((sprite_ptr)&tactical_spr,0,0,38,28,0,0,0,0,0,0);
  661.  
  662. // extract the bitmaps for heads up text
  663.  
  664. for (index=0; index<5; index++)
  665.     PCX_Get_Sprite((pcx_picture_ptr)&image_pcx,
  666.                    (sprite_ptr)&tactical_spr,index,index,0);
  667.  
  668. // delete pcx file
  669.  
  670. PCX_Delete((pcx_picture_ptr)&image_pcx);
  671.  
  672. // load the imagery for the control buttons
  673.  
  674. PCX_Init((pcx_picture_ptr)&image_pcx);
  675. PCX_Load("krkbutt.pcx", (pcx_picture_ptr)&image_pcx,1);
  676.  
  677. // intialize the tactical sprite
  678.  
  679. Sprite_Init((sprite_ptr)&buttons_spr,0,0,42,12,0,0,0,0,0,0);
  680.  
  681. // extract the bitmaps for heads up text
  682.  
  683. for (index=0; index<8; index++)
  684.     PCX_Get_Sprite((pcx_picture_ptr)&image_pcx,
  685.                    (sprite_ptr)&buttons_spr,index,index%4,index/4);
  686.  
  687. // delete pcx file
  688.  
  689. PCX_Delete((pcx_picture_ptr)&image_pcx);
  690.  
  691. } // end Load_Tactical
  692.  
  693. //////////////////////////////////////////////////////////////////////////////
  694.  
  695. void Draw_Scanner(int command)
  696. {
  697.  
  698. // this function draws the scanner, it has three modes, clear, erase blips,
  699. // and draw blips
  700.  
  701. int index,  // looping variable
  702.     xb,yb;  // temporary blip locations
  703.  
  704. // holds the scanner clips
  705.  
  706. static int blip_x[24],      // these arrays hold the blips from call to call
  707.            blip_y[24],
  708.            active_blips=0;  // totall number of active blips this frame
  709.  
  710. // what is the command
  711.  
  712. if (command==SCANNER_CLEAR)
  713.    {
  714.    // clear the scanner image
  715.  
  716.    Draw_Rectangle(SCANNER_X,
  717.                   SCANNER_Y,
  718.                   SCANNER_X+SCANNER_WIDTH-1,
  719.                   SCANNER_Y+SCANNER_HEIGHT-1,
  720.                   0);
  721.  
  722.    // reset number of blips
  723.  
  724.    active_blips=0;
  725.  
  726.    // exit
  727.  
  728.    return;
  729.  
  730.    } // end if clear
  731.  
  732. if (command==SCANNER_LOGO)
  733.    {
  734.    // clear the scanner surface off
  735.  
  736.    tactical_spr.curr_frame = 1;
  737.    tactical_spr.x          = SCANNER_X + 8;
  738.    tactical_spr.y          = SCANNER_Y + 6;
  739.  
  740.    Sprite_Draw((sprite_ptr)&tactical_spr, video_buffer,0);
  741.  
  742.    // reset number of blips
  743.  
  744.    active_blips=0;
  745.  
  746.    // exit
  747.  
  748.    return;
  749.  
  750.    } // end if
  751.  
  752. // now determine if scanner is being drawn or erased
  753.  
  754. if (command==SCANNER_ERASE_BLIPS)
  755.    {
  756.    // erase all the scanner blips
  757.  
  758.    // simply loop thru blips and erase them
  759.  
  760.    for (index=0; index<active_blips; index++)
  761.        Write_Pixel(blip_x[index],blip_y[index],0);
  762.  
  763.    return;
  764.  
  765.    } // end if
  766. else
  767.    {
  768.    // reset number of active blips
  769.  
  770.    active_blips = 0;
  771.  
  772.    // draw all the scanner blips
  773.  
  774.    // first barriers
  775.  
  776.    for (index=0; index<NUM_BARRIERS; index++)
  777.        {
  778.        // compute blip position
  779.  
  780.        xb = SCANNER_X+(8000+barriers[index].x)/282;
  781.        yb = SCANNER_Y+(8000-barriers[index].z)/382;
  782.  
  783.        // draw the blip
  784.  
  785.        Write_Pixel(xb,yb,7);
  786.  
  787.        // save the blip
  788.  
  789.        blip_x[active_blips] = xb;
  790.        blip_y[active_blips] = yb;
  791.  
  792.        // increment number of blips
  793.  
  794.        active_blips++;
  795.  
  796.        } // end for index
  797.  
  798.    // now telepods
  799.  
  800.    for (index=0; index<NUM_TELEPODS; index++)
  801.        {
  802.        // compute blip position
  803.  
  804.        xb = SCANNER_X+(8000+telepods[index].x)/282;
  805.        yb = SCANNER_Y+(8000-telepods[index].z)/382;
  806.  
  807.        // draw the blip
  808.  
  809.        Write_Pixel(xb,yb,5);
  810.  
  811.        // save the blip
  812.  
  813.        blip_x[active_blips] = xb;
  814.        blip_y[active_blips] = yb;
  815.  
  816.        // increment number of blips
  817.  
  818.        active_blips++;
  819.  
  820.        } // end for index
  821.  
  822.    // now power stations
  823.  
  824.    for (index=0; index<NUM_STATIONS; index++)
  825.        {
  826.        // compute blip position
  827.  
  828.        xb = SCANNER_X+(8000+stations[index].x)/282;
  829.        yb = SCANNER_Y+(8000-stations[index].z)/382;
  830.  
  831.        // draw the blip
  832.  
  833.        Write_Pixel(xb,yb,13);
  834.  
  835.        // save the blip
  836.  
  837.        blip_x[active_blips] = xb;
  838.        blip_y[active_blips] = yb;
  839.  
  840.        // increment number of blips
  841.  
  842.        active_blips++;
  843.  
  844.        } // end for index
  845.  
  846.    // now aliens
  847.  
  848.    for (index=0; index<NUM_ALIENS; index++)
  849.        {
  850.  
  851.        if (aliens[index].state!=ALIEN_DEAD)
  852.           {
  853.  
  854.           // compute blip position
  855.  
  856.           xb = SCANNER_X+(8000+aliens[index].x)/282;
  857.           yb = SCANNER_Y+(8000-aliens[index].z)/382;
  858.  
  859.           // draw the blip
  860.  
  861.           Write_Pixel(xb,yb,12);
  862.  
  863.           // save the blip
  864.  
  865.           blip_x[active_blips] = xb;
  866.           blip_y[active_blips] = yb;
  867.  
  868.           // increment number of blips
  869.  
  870.           active_blips++;
  871.  
  872.           } // end if
  873.  
  874.        } // end for index
  875.  
  876.    // finally the player
  877.  
  878.    // compute blip position
  879.  
  880.    xb = SCANNER_X+(8000+view_point.x)/282;
  881.    yb = SCANNER_Y+(8000-view_point.z)/382;
  882.  
  883.    // draw the blip
  884.  
  885.    Write_Pixel(xb,yb,9);
  886.  
  887.    // save the blip
  888.  
  889.    blip_x[active_blips] = xb;
  890.    blip_y[active_blips] = yb;
  891.  
  892.    // increment number of blips
  893.  
  894.    active_blips++;
  895.  
  896.    } // end else
  897.  
  898. } // end Draw_Scanner
  899.  
  900. //////////////////////////////////////////////////////////////////////////////
  901.  
  902. void Init_Missiles(void)
  903. {
  904. // this function resets the missile array and gets them ready for use
  905.  
  906. int index; // looping variable
  907.  
  908. // initialize all missiles to a known state
  909.  
  910. for (index=0; index<NUM_MISSILES; index++)
  911.     {
  912.  
  913.     missiles[index].state       = MISSILE_INACTIVE;
  914.     missiles[index].owner       = NO_OWNER;
  915.     missiles[index].lifetime    = 0;
  916.  
  917.     missiles[index].direction.x = 0;
  918.     missiles[index].direction.y = 0;
  919.     missiles[index].direction.z = 0;
  920.  
  921.     missiles[index].x           = 0;
  922.     missiles[index].y           = 0;
  923.     missiles[index].z           = 0;
  924.  
  925.     } // end for index
  926.  
  927. // reset number of active missiles
  928.  
  929. active_player_missiles = 0;
  930. total_active_missiles  = 0;
  931.  
  932. } // end Init_Missiles
  933.  
  934. /////////////////////////////////////////////////////////////////////////////
  935.  
  936. void Move_Missiles(void)
  937. {
  938. // this function moves all the missiles
  939.  
  940. int index,            // looping variables
  941.     index_2,
  942.     radius_tallon,    // used to hold the radius of the ships
  943.     radius_slider,
  944.     radius_player,
  945.     dx,               // used during distance calculations
  946.     dz,
  947.     dist,
  948.     min;
  949.  
  950. // pre-compute radi of alien ship types
  951.  
  952. radius_tallon = (0.75*dynamic_obj[TALLONS_TEMPLATE].radius);
  953. radius_slider = (0.75*dynamic_obj[SLIDERS_TEMPLATE].radius);
  954.  
  955. // compute radius of players ship
  956.  
  957. if (players_ship_type==PLAYER_TALLON)
  958.    radius_player = dynamic_obj[TALLONS_TEMPLATE].radius;
  959. else
  960.    radius_player = dynamic_obj[SLIDERS_TEMPLATE].radius;
  961.  
  962. // move all the missiles and test for collisions
  963.  
  964. for (index=0; index<NUM_MISSILES; index++)
  965.     {
  966.     // for each missile that is active, move it and test it against bounds
  967.     // and lifetime
  968.  
  969.     if (missiles[index].state==MISSILE_ACTIVE)
  970.        {
  971.        // process missile
  972.  
  973.        // first move missile
  974.  
  975.        missiles[index].x+=missiles[index].direction.x;
  976.        missiles[index].y+=missiles[index].direction.y;
  977.        missiles[index].z+=missiles[index].direction.z;
  978.  
  979.        // test for collisions with aliens if player fired this missile
  980.  
  981.        if (missiles[index].owner==PLAYER_OWNER)
  982.           {
  983.           for (index_2=0; index_2<NUM_ALIENS; index_2++)
  984.               {
  985.  
  986.               // test if alien is not dead or dying
  987.  
  988.               if (aliens[index_2].state!=ALIEN_DEAD &&
  989.                   aliens[index_2].state!=ALIEN_DYING)
  990.                  {
  991.  
  992.                  // test if missiles center is within bounding radius
  993.                  // of alien ship
  994.  
  995.                  // compute distance based on taylor expansion about 12% error
  996.                  // max
  997.  
  998.                  // first find |dx| and |dz|
  999.  
  1000.                  if ( (dx = ((int)aliens[index_2].x - (int)missiles[index].x) ) < 0)
  1001.                     dx=-dx;
  1002.  
  1003.                  if ( (dz = ((int)aliens[index_2].z - (int)missiles[index].z)) < 0)
  1004.                     dz=-dz;
  1005.  
  1006.                  // compute minimum delta
  1007.  
  1008.                  if (dx<=dz)
  1009.                     min=dx;
  1010.                  else
  1011.                     min=dz;
  1012.  
  1013.                  // compute distance
  1014.  
  1015.                  dist = dx + dz - (min >> 1);
  1016.  
  1017.                  // test distance against average radius of alien ship
  1018.  
  1019.                  if (aliens[index_2].type==ALIEN_TALLON)
  1020.                     {
  1021.                     if (dist<=radius_tallon)
  1022.                        {
  1023.                        // kill missile
  1024.  
  1025.                        missiles[index].lifetime=-1;
  1026.  
  1027.                        // send message to aliens that this one is dying
  1028.  
  1029.                        aliens[index_2].state       = ALIEN_DYING;
  1030.                        aliens[index_2].counter_1   = 0;
  1031.                        aliens[index_2].threshold_1 = 20;
  1032.  
  1033.                        aliens[index_2].speed         = 0;
  1034.  
  1035.                        aliens[index_2].color.red   = 0;
  1036.                        aliens[index_2].color.green = 0;
  1037.                        aliens[index_2].color.blue  = 0;
  1038.  
  1039.                        // lets hear him fry
  1040.  
  1041.                        Digital_FX_Play(KRKEX1_VOC,0);
  1042.  
  1043.                        // add one more notch to my 6 shooter!
  1044.  
  1045.                        ship_kills++;
  1046.  
  1047.                        // move to next missile
  1048.  
  1049.                        continue;
  1050.  
  1051.                        } // end if
  1052.  
  1053.                     } // end if tallon
  1054.                  else
  1055.                  if (aliens[index_2].type==ALIEN_SLIDER)
  1056.                     {
  1057.                     if (dist<=radius_slider)
  1058.                        {
  1059.                        // kill missile
  1060.  
  1061.                        missiles[index].lifetime=-1;
  1062.  
  1063.                        // send message to aliens that this one is dying
  1064.  
  1065.                        aliens[index_2].state       = ALIEN_DYING;
  1066.                        aliens[index_2].counter_1   = 0;
  1067.                        aliens[index_2].threshold_1 = 20;
  1068.  
  1069.                        aliens[index_2].speed       = 0;
  1070.  
  1071.                        aliens[index_2].color.red   = 0;
  1072.                        aliens[index_2].color.green = 0;
  1073.                        aliens[index_2].color.blue  = 0;
  1074.  
  1075.                        // lets hear him fry
  1076.  
  1077.                        Digital_FX_Play(KRKEX1_VOC,0);
  1078.  
  1079.                        // add one more notch to my 6 shooter!
  1080.  
  1081.                        ship_kills++;
  1082.  
  1083.                        // move to next missile
  1084.  
  1085.                        continue;
  1086.  
  1087.                        } // end if
  1088.  
  1089.                     } // end if slider
  1090.  
  1091.                  } // end if alien not dead
  1092.  
  1093.               } // end for
  1094.  
  1095.           } // end if player fired missile
  1096.        else
  1097.           {
  1098.           // this missile must be an aliens, so test it against ship
  1099.  
  1100.           if ( (dx = ((int)view_point.x - (int)missiles[index].x) ) < 0)
  1101.              dx=-dx;
  1102.  
  1103.           if ( (dz = ((int)view_point.z - (int)missiles[index].z)) < 0)
  1104.              dz=-dz;
  1105.  
  1106.           // compute minimum delta
  1107.  
  1108.           if (dx<=dz)
  1109.              min=dx;
  1110.           else
  1111.              min=dz;
  1112.  
  1113.           // compute distance
  1114.  
  1115.           dist = dx + dz - (min >> 1);
  1116.  
  1117.           // test for collision
  1118.  
  1119.           if (dist<=radius_player)
  1120.              {
  1121.              // send message to player
  1122.  
  1123.              ship_message = SHIP_HIT;
  1124.              ship_timer   = 25;
  1125.  
  1126.              // add some sound
  1127.  
  1128.              Digital_FX_Play(KRKEX2_VOC,0);
  1129.  
  1130.              // add some damage
  1131.  
  1132.              if (++ship_damage>50)
  1133.                 ship_damage=50;
  1134.  
  1135.              // kill missile
  1136.  
  1137.              missiles[index].lifetime=-1;
  1138.  
  1139.              } // end if collision
  1140.  
  1141.           } // end else alien
  1142.  
  1143.        // test for out of bounds
  1144.  
  1145.        if (missiles[index].x > GAME_MAX_WORLD_X+500 ||
  1146.            missiles[index].x < GAME_MIN_WORLD_X-500 ||
  1147.  
  1148.            missiles[index].z > GAME_MAX_WORLD_Z+500 ||
  1149.            missiles[index].z < GAME_MIN_WORLD_Z-500 )
  1150.            {
  1151.  
  1152.            // de-activate missile
  1153.  
  1154.            missiles[index].state = MISSILE_INACTIVE;
  1155.  
  1156.            if (missiles[index].owner==PLAYER_OWNER)
  1157.               active_player_missiles--;
  1158.  
  1159.            // decrement total always
  1160.  
  1161.            total_active_missiles--;
  1162.  
  1163.            } // end if
  1164.        else
  1165.        if ((--missiles[index].lifetime)<0)
  1166.            {
  1167.            // missile has died out (ran out of energy)
  1168.  
  1169.            missiles[index].state = MISSILE_INACTIVE;
  1170.  
  1171.            if (missiles[index].owner==PLAYER_OWNER)
  1172.               active_player_missiles--;
  1173.  
  1174.            // decrement total always
  1175.  
  1176.            total_active_missiles--;
  1177.  
  1178.            } // end if
  1179.  
  1180.        } // end if missile alive
  1181.  
  1182.     } // end for index
  1183.  
  1184. // only rotate if there are active missiles
  1185.  
  1186. if (total_active_missiles)
  1187.    Rotate_Object(&dynamic_obj[MISSILES_TEMPLATE],0,0,30);
  1188.  
  1189. } // end Move_Missiles
  1190.  
  1191. /////////////////////////////////////////////////////////////////////////////
  1192.  
  1193. void Draw_Missiles(void)
  1194. {
  1195. // this function draws all the missiles (in 3d)
  1196.  
  1197. int index; // looping variable
  1198.  
  1199. for (index=0; index<NUM_MISSILES; index++)
  1200.     {
  1201.     // test if missile is active before starting 3-D processing
  1202.  
  1203.     if (missiles[index].state==MISSILE_ACTIVE)
  1204.        {
  1205.  
  1206.        // test if object is visible
  1207.  
  1208.        // now before we continue to process object, we must
  1209.        // move it to the proper world position
  1210.  
  1211.        dynamic_obj[MISSILES_TEMPLATE].world_pos.x = missiles[index].x;
  1212.        dynamic_obj[MISSILES_TEMPLATE].world_pos.y = missiles[index].y;
  1213.        dynamic_obj[MISSILES_TEMPLATE].world_pos.z = missiles[index].z;
  1214.  
  1215.        if (!Remove_Object(&dynamic_obj[MISSILES_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  1216.           {
  1217.           // convert object local coordinates to world coordinate
  1218.  
  1219.           Local_To_World_Object(&dynamic_obj[MISSILES_TEMPLATE]);
  1220.  
  1221.           // remove the backfaces and shade object
  1222.  
  1223.           Remove_Backfaces_And_Shade(&dynamic_obj[MISSILES_TEMPLATE],-1);
  1224.  
  1225.           // convert world coordinates to camera coordinate
  1226.  
  1227.           World_To_Camera_Object(&dynamic_obj[MISSILES_TEMPLATE]);
  1228.  
  1229.           // clip the objects polygons against viewing volume
  1230.  
  1231.           Clip_Object_3D(&dynamic_obj[MISSILES_TEMPLATE],CLIP_Z_MODE);
  1232.  
  1233.           // generate the final polygon list
  1234.  
  1235.           Generate_Poly_List(&dynamic_obj[MISSILES_TEMPLATE],ADD_TO_POLY_LIST);
  1236.  
  1237.           } // end if object is outside viewing volume
  1238.  
  1239.        } // end if missile active
  1240.  
  1241.     } // end for index
  1242.  
  1243. } // end Draw_Missiles
  1244.  
  1245. //////////////////////////////////////////////////////////////////////////////
  1246.  
  1247. int Start_Missile(int owner,
  1248.                   vector_3d_ptr pos,
  1249.                   vector_3d_ptr dir,
  1250.                   int speed,
  1251.                   int lifetime)
  1252. {
  1253. // this function starts a missile up by hunting for a unused missile, initializing
  1254. // it and then starting it with the proper parameters
  1255.  
  1256. int index; // looping variable
  1257.  
  1258. // first test if this is a missile fired by player, if so, test if player
  1259. // is getting greedy
  1260.  
  1261. if (owner==PLAYER_OWNER && active_player_missiles>=MAX_PLAYER_MISSILES)
  1262.    return(0);
  1263.  
  1264. // hunt for an inactive missile
  1265.  
  1266. for (index=0; index<NUM_MISSILES; index++)
  1267.     {
  1268.     // is this missile free?
  1269.  
  1270.     if (missiles[index].state==MISSILE_INACTIVE)
  1271.        {
  1272.  
  1273.        // set this missile up
  1274.  
  1275.        missiles[index].state       = MISSILE_ACTIVE;
  1276.        missiles[index].owner       = owner;
  1277.        missiles[index].lifetime    = lifetime;
  1278.  
  1279.        missiles[index].direction.x = speed*dir->x;
  1280.        missiles[index].direction.y = speed*dir->y;
  1281.        missiles[index].direction.z = speed*dir->z;
  1282.  
  1283.        // start missile at center of viewport plus one step out
  1284.  
  1285.        missiles[index].x           =            pos->x+dir->x;
  1286.        missiles[index].y           = GUN_HEIGHT+pos->y+dir->y;
  1287.        missiles[index].z           =            pos->z+dir->z;
  1288.  
  1289.        // test if player fired the missile and update active missiles
  1290.  
  1291.        if (owner==PLAYER_OWNER)
  1292.           {
  1293.           // there's now one more missile
  1294.           active_player_missiles++;
  1295.  
  1296.           // play sound fx
  1297.  
  1298.           Digital_FX_Play(KRKMIS_VOC,2);
  1299.  
  1300.           }
  1301.        else
  1302.           {
  1303.           // must be alien
  1304.  
  1305.           // play sound fx
  1306.  
  1307.           Digital_FX_Play(KRKEMIS_VOC,3);
  1308.  
  1309.           } // end else
  1310.  
  1311.        // increment total active missiles
  1312.  
  1313.        total_active_missiles++;
  1314.  
  1315.        // exit loop baby!
  1316.  
  1317.        return(1);
  1318.  
  1319.        } // end if
  1320.  
  1321.     } // end for index
  1322.  
  1323. // couldn't satisfy request, let caller know
  1324.  
  1325. return(0);
  1326.  
  1327. } // end Start_Missile
  1328.  
  1329. //////////////////////////////////////////////////////////////////////////////
  1330.  
  1331. void Init_Aliens(void)
  1332. {
  1333. // this function initializes the alien structures
  1334.  
  1335. int index; // looping variable
  1336.  
  1337. for (index=0; index<NUM_ALIENS; index++)
  1338.     {
  1339.  
  1340.     aliens[index].state           = ALIEN_NEW_STATE;
  1341.     aliens[index].counter_1       = 0;
  1342.     aliens[index].counter_2       = 0;
  1343.     aliens[index].threshold_1     = 0;
  1344.     aliens[index].threshold_2     = 0;
  1345.     aliens[index].aux_1           = 0;
  1346.     aliens[index].aux_2           = 0;
  1347.     aliens[index].color_reg       = ALIEN_EXPL_BASE_REG+index;
  1348.  
  1349.  
  1350.     aliens[index].color.red       = 0;
  1351.     aliens[index].color.green     = 0;
  1352.     aliens[index].color.blue      = 0;
  1353.  
  1354.     aliens[index].type            = index%2;
  1355.     aliens[index].speed           = 0;
  1356.  
  1357.     aliens[index].angular_heading = 0;
  1358.  
  1359.     aliens[index].direction.x     = 0;
  1360.     aliens[index].direction.y     = 0;
  1361.     aliens[index].direction.z     = 0;
  1362.  
  1363.     aliens[index].x               = -2000 + rand()%4000;
  1364.     aliens[index].y               = 0;
  1365.     aliens[index].z               = -2000 + rand()%4000;
  1366.  
  1367.     } // end for index
  1368.  
  1369. } // end Init_Aliens
  1370.  
  1371. //////////////////////////////////////////////////////////////////////////////
  1372.  
  1373. void Process_Aliens(void)
  1374. {
  1375. // this function performs AI for the aliens and transforms them
  1376.  
  1377. int index,      // looping variable
  1378.     which_pod;  // used to select which telepod to start a dead alien at
  1379.  
  1380. float head_x,   // used to compute final heading of alien
  1381.       head_z,
  1382.       target_x, // used to compute desired target heading for alien
  1383.       target_z,
  1384.       normal_y, // the y component of a normal vector
  1385.       distance; // distance between alien and player
  1386.  
  1387.  
  1388. vector_3d alien_pos,    // temp to hold alien position
  1389.           alien_dir;    // temp to hold alien direction
  1390.  
  1391. // this holds the aliens personality probability table.
  1392. // here are the meanings of the values and the current distribution
  1393.  
  1394. // 0 attack, 30%
  1395. // 1 random, 20%
  1396. // 2 evade,  10%
  1397. // 3 stop,   10%
  1398. // 4 turn,   20%
  1399.  
  1400. static int alien_personality[10]={0,1,4,0,1,4,3,0,2,3};
  1401.  
  1402. // first process live aliens
  1403.  
  1404. for (index=0; index<NUM_ALIENS; index++)
  1405.     {
  1406.     // is this alien alive?
  1407.  
  1408.     if (aliens[index].state!=ALIEN_DEAD)
  1409.        {
  1410.  
  1411.        // based on state of alien, do the right thing
  1412.  
  1413.        switch(aliens[index].state)
  1414.              {
  1415.              case ALIEN_DEAD:
  1416.                   {
  1417.                   // process dead state
  1418.  
  1419.                   aliens[index].state = ALIEN_NEW_STATE;
  1420.  
  1421.                   } break;
  1422.  
  1423.              case ALIEN_DYING:
  1424.                   {
  1425.                   // continue dying
  1426.  
  1427.                   // increase intensity of color
  1428.  
  1429.                   if ((aliens[index].color.green+=4)>63)
  1430.                       aliens[index].color.green = 63;
  1431.  
  1432.                   // set color register
  1433.  
  1434.                   Write_Color_Reg(aliens[index].color_reg,(RGB_color_ptr)&aliens[index].color);
  1435.  
  1436.                   // is death sequence complete?
  1437.  
  1438.                   if (++aliens[index].counter_1 > aliens[index].threshold_1)
  1439.                      {
  1440.                      // tell state machine to select a new state
  1441.  
  1442.                      aliens[index].state = ALIEN_DEAD;
  1443.  
  1444.                      Write_Color_Reg(aliens[index].color_reg,(RGB_color_ptr)&black);
  1445.  
  1446.                      } // end if
  1447.  
  1448.                   } break;
  1449.  
  1450.              case ALIEN_NEW_STATE:
  1451.                   {
  1452.  
  1453.                   // a new state has been requested, select a new state based
  1454.                   // on probability and personality
  1455.  
  1456.                   switch(alien_personality[rand()%10])
  1457.                         {
  1458.                         case 0: // attack
  1459.  
  1460.                              {
  1461.                              // the alien is going to attack the player
  1462.  
  1463.                              // how long for total state
  1464.  
  1465.                              aliens[index].counter_1   = 0;
  1466.                              aliens[index].threshold_1 = 50 + rand()%150;
  1467.  
  1468.                              // set time between heading adjustements
  1469.  
  1470.                              aliens[index].counter_2   = 0;
  1471.                              aliens[index].threshold_2 = 3 + rand()%5;
  1472.  
  1473.                              // set speed
  1474.  
  1475.                              aliens[index].speed = 45 + rand()%5;
  1476.  
  1477.                              // set new state
  1478.  
  1479.                              aliens[index].state = ALIEN_ATTACK;
  1480.  
  1481.                              } break;
  1482.  
  1483.                         case 1:  // random
  1484.                              {
  1485.  
  1486.                              // how long for total state
  1487.  
  1488.                              aliens[index].counter_1   = 0;
  1489.                              aliens[index].threshold_1 = 50 + rand()%150;
  1490.  
  1491.                              // how often for random direction changes
  1492.  
  1493.                              aliens[index].counter_2   = 0;
  1494.                              aliens[index].threshold_2 = 10 + rand()%50;
  1495.  
  1496.                              // set speed
  1497.  
  1498.                              aliens[index].speed = 40 + rand()%25;
  1499.  
  1500.                              // and set new state
  1501.  
  1502.                              aliens[index].state = ALIEN_RANDOM;
  1503.  
  1504.                              } break;
  1505.  
  1506.                         case 2:  // evade
  1507.                              {
  1508.  
  1509.                              // how long for total state
  1510.  
  1511.                              aliens[index].counter_1   = 0;
  1512.                              aliens[index].threshold_1 = 50 + rand()%150;
  1513.  
  1514.                              // set time between heading adjustements
  1515.  
  1516.                              aliens[index].counter_2   = 0;
  1517.                              aliens[index].threshold_2 = 3 + rand()%5;
  1518.  
  1519.                              // set speed
  1520.  
  1521.                              aliens[index].speed = 50 + rand()%5;
  1522.  
  1523.                              // set new state
  1524.  
  1525.                              aliens[index].state = ALIEN_EVADE;
  1526.  
  1527.                              } break;
  1528.  
  1529.                         case 3: // stop
  1530.                              {
  1531.                              // set number of frames for alien to stop
  1532.  
  1533.                              aliens[index].counter_1   = 0;
  1534.                              aliens[index].threshold_1 = 5 + rand()%10;
  1535.  
  1536.                              // set speed to 0
  1537.  
  1538.                              aliens[index].speed = 0;
  1539.  
  1540.                              // and set new state
  1541.  
  1542.                              aliens[index].state = ALIEN_STOP;
  1543.  
  1544.                              } break;
  1545.  
  1546.  
  1547.                         case 4:  // turn
  1548.                              {
  1549.  
  1550.                              // set amount of time for turn
  1551.  
  1552.                              aliens[index].counter_1   = 0;
  1553.                              aliens[index].threshold_1 = 20 + rand()%20;
  1554.  
  1555.                              // set angular turning rate
  1556.  
  1557.                              aliens[index].aux_1 = -5+rand()%11;
  1558.  
  1559.                              // set speed for turn
  1560.  
  1561.                              aliens[index].speed = 35+rand()%30;
  1562.  
  1563.                              // and set new state
  1564.  
  1565.                              aliens[index].state = ALIEN_TURN;
  1566.  
  1567.                              } break;
  1568.  
  1569.                         default: break;
  1570.  
  1571.                         } // end switch
  1572.  
  1573.                   } break;
  1574.  
  1575.              case ALIEN_ATTACK:
  1576.                   {
  1577.                   // continue tracking player
  1578.  
  1579.                   // test if it's time to adjust heading to track player
  1580.  
  1581.                   if (++aliens[index].counter_2 > aliens[index].threshold_2)
  1582.                      {
  1583.  
  1584.                      // adjust heading toward player, use a heuristic approach
  1585.                      // that simply tries to keep turing the alien toward
  1586.                      // the player, later maybe we could add a bit of
  1587.                      // trajectory lookahead, so the alien could intercept
  1588.                      // the player???
  1589.  
  1590.  
  1591.                      // to determine which way the alien needs to turn we
  1592.                      // can use the following trick: based on the current
  1593.                      // trajectory of the alien and the vector from the
  1594.                      // alien to the player, we can compute a normal vector
  1595.  
  1596.                      // compute heading vector (happens to be a unit vector)
  1597.  
  1598.                      head_x = sin_look[aliens[index].angular_heading];
  1599.                      head_z = cos_look[aliens[index].angular_heading];
  1600.  
  1601.                      // compute target trajectory vector, players position
  1602.                      // minus aliens position
  1603.  
  1604.                      target_x = view_point.x - aliens[index].x;
  1605.                      target_z = view_point.z - aliens[index].z;
  1606.  
  1607.                      // now compute y component of normal
  1608.  
  1609.                      normal_y = (head_z*target_x - head_x*target_z);
  1610.  
  1611.                      // based on the sign of the result we can determine if
  1612.                      // we should turn the alien right or left, but be careful
  1613.                      // we are in a LEFT HANDED system!
  1614.  
  1615.                      if (normal_y>=0)
  1616.                         aliens[index].angular_heading+=(10+rand()%10);
  1617.                      else
  1618.                         aliens[index].angular_heading-=(10+rand()%10);
  1619.  
  1620.                      // check angle for overflow/underflow
  1621.  
  1622.                      if (aliens[index].angular_heading >=360)
  1623.                         aliens[index].angular_heading-=360;
  1624.                      else
  1625.                      if (aliens[index].angular_heading < 0)
  1626.                         aliens[index].angular_heading+=360;
  1627.  
  1628.                      // reset counter
  1629.  
  1630.                      aliens[index].counter_2 = 0;
  1631.  
  1632.                      } // end if
  1633.  
  1634.                   // test if attacking sequence is complete
  1635.  
  1636.                   if (++aliens[index].counter_1 > aliens[index].threshold_1)
  1637.                      {
  1638.                      // tell state machine to select a new state
  1639.  
  1640.                      aliens[index].state = ALIEN_NEW_STATE;
  1641.  
  1642.                      } // end if
  1643.  
  1644.                   // try and fire a missile
  1645.  
  1646.                   distance = fabs(view_point.x - aliens[index].x) +
  1647.                              fabs(view_point.z - aliens[index].z);
  1648.  
  1649.                   if ((rand()%15)==1 && distance<3500)
  1650.                      {
  1651.                      // create local vectors
  1652.  
  1653.                      // first position
  1654.  
  1655.                      alien_pos.x = aliens[index].x;
  1656.                      alien_pos.y = 45; // alien y centerline
  1657.                      alien_pos.z = aliens[index].z;
  1658.  
  1659.                      // now direction
  1660.  
  1661.                      alien_dir.x = sin_look[aliens[index].angular_heading];
  1662.                      alien_dir.y = 0;
  1663.                      alien_dir.z = cos_look[aliens[index].angular_heading];
  1664.  
  1665.                      // start the missle
  1666.  
  1667.                      Start_Missile(ALIEN_OWNER,
  1668.                                    &alien_pos,
  1669.                                    &alien_dir,
  1670.                                    aliens[index].speed+25,
  1671.                                    75);
  1672.  
  1673.                      } // end if fire a missile
  1674.  
  1675.                   } break;
  1676.  
  1677.              case ALIEN_RANDOM:
  1678.                   {
  1679.                   // continue moving in randomly selected direction
  1680.  
  1681.                   // test if it's time to select a new direction
  1682.  
  1683.                   if (++aliens[index].counter_2 > aliens[index].threshold_2)
  1684.                      {
  1685.  
  1686.                      // select a new direction  +- 30 degrees
  1687.  
  1688.                      aliens[index].angular_heading+=(-30 + 10*rand()%7);
  1689.  
  1690.                      // check angle for overflow/underflow
  1691.  
  1692.                      if (aliens[index].angular_heading >=360)
  1693.                         aliens[index].angular_heading-=360;
  1694.                      else
  1695.                      if (aliens[index].angular_heading < 0)
  1696.                         aliens[index].angular_heading+=360;
  1697.  
  1698.                      // reset counter
  1699.  
  1700.                      aliens[index].counter_2 = 0;
  1701.  
  1702.                      } // end if
  1703.  
  1704.                   // test if entire random sequence is complete
  1705.  
  1706.                   if (++aliens[index].counter_1 > aliens[index].threshold_1)
  1707.                      {
  1708.                      // tell state machine to select a new state
  1709.  
  1710.                      aliens[index].state = ALIEN_NEW_STATE;
  1711.  
  1712.                      } // end if
  1713.  
  1714.                   } break;
  1715.  
  1716.              case ALIEN_EVADE:
  1717.                   {
  1718.                   // continue evading player
  1719.  
  1720.                   // test if it's time to adjust heading to evade player
  1721.  
  1722.                   if (++aliens[index].counter_2 > aliens[index].threshold_2)
  1723.                      {
  1724.  
  1725.                      // adjust heading away from player, use a heuristic approach
  1726.                      // that simply tries to keep turing the alien away from
  1727.                      // the player
  1728.  
  1729.                      // to determine which way the alien needs to turn we
  1730.                      // can use the following trick: based on the current
  1731.                      // trajectory of the alien and the vector from the
  1732.                      // alien to the player, we can compute a normal vector
  1733.  
  1734.                      // compute heading vector (happens to be a unit vector)
  1735.  
  1736.                      head_x = sin_look[aliens[index].angular_heading];
  1737.                      head_z = cos_look[aliens[index].angular_heading];
  1738.  
  1739.                      // compute target trajectory vector, players position
  1740.                      // minus aliens position
  1741.  
  1742.                      target_x = view_point.x - aliens[index].x;
  1743.                      target_z = view_point.z - aliens[index].z;
  1744.  
  1745.                      // now compute y component of normal
  1746.  
  1747.                      normal_y = (head_z*target_x - head_x*target_z);
  1748.  
  1749.                      // based on the sign of the result we can determine if
  1750.                      // we should turn the alien right or left, but be careful
  1751.                      // we are in a LEFT HANDED system!
  1752.  
  1753.                      if (normal_y>=0)
  1754.                         aliens[index].angular_heading-=(10+rand()%10);
  1755.                      else
  1756.                         aliens[index].angular_heading+=(10+rand()%10);
  1757.  
  1758.                      // check angle for overflow/underflow
  1759.  
  1760.                      if (aliens[index].angular_heading >=360)
  1761.                         aliens[index].angular_heading-=360;
  1762.                      else
  1763.                      if (aliens[index].angular_heading < 0)
  1764.                         aliens[index].angular_heading+=360;
  1765.  
  1766.                      // reset counter
  1767.  
  1768.                      aliens[index].counter_2 = 0;
  1769.  
  1770.                      } // end if
  1771.  
  1772.                   // test if attacking sequence is complete
  1773.  
  1774.                   if (++aliens[index].counter_1 > aliens[index].threshold_1)
  1775.                      {
  1776.                      // tell state machine to select a new state
  1777.  
  1778.                      aliens[index].state = ALIEN_NEW_STATE;
  1779.  
  1780.                      } // end if
  1781.  
  1782.                   } break;
  1783.  
  1784.              case ALIEN_STOP:
  1785.                   {
  1786.                   // sit still and rotate
  1787.  
  1788.                   // test if stopping sequence is complete
  1789.  
  1790.                   if (++aliens[index].counter_1 > aliens[index].threshold_1)
  1791.                      {
  1792.                      // tell state machine to select a new state
  1793.  
  1794.                      aliens[index].state = ALIEN_NEW_STATE;
  1795.  
  1796.                      } // end if
  1797.  
  1798.                   } break;
  1799.  
  1800.              case ALIEN_TURN:
  1801.                   {
  1802.                   // continue turn
  1803.  
  1804.                   aliens[index].angular_heading+=aliens[index].aux_1;
  1805.  
  1806.                   // check angle for overflow/underflow
  1807.  
  1808.                   if (aliens[index].angular_heading >=360)
  1809.                      aliens[index].angular_heading-=360;
  1810.                   else
  1811.                   if (aliens[index].angular_heading < 0)
  1812.                      aliens[index].angular_heading+=360;
  1813.  
  1814.                   // test if turning sequence is complete
  1815.  
  1816.                   if (++aliens[index].counter_1 > aliens[index].threshold_1)
  1817.                      {
  1818.                      // tell state machine to select a new state
  1819.  
  1820.                      aliens[index].state = ALIEN_NEW_STATE;
  1821.  
  1822.                      } // end if
  1823.  
  1824.                   } break;
  1825.  
  1826.              default: break;
  1827.  
  1828.              } // end switch
  1829.  
  1830.        // now move the alien based on direction
  1831.  
  1832.        aliens[index].x +=  (aliens[index].speed*sin_look[aliens[index].angular_heading]);
  1833.        aliens[index].z +=  (aliens[index].speed*cos_look[aliens[index].angular_heading]);
  1834.  
  1835.        // perform bounds checking, if an alien hits an edge warp to other side
  1836.  
  1837.        if (aliens[index].x>(GAME_MAX_WORLD_X+750))
  1838.            aliens[index].x=(GAME_MIN_WORLD_X-500);
  1839.        else
  1840.        if (aliens[index].x<(GAME_MIN_WORLD_X-750))
  1841.            aliens[index].x=(GAME_MAX_WORLD_X+500);
  1842.  
  1843.        if (aliens[index].z>(GAME_MAX_WORLD_Z+750))
  1844.            aliens[index].z=(GAME_MIN_WORLD_Z-500);
  1845.        else
  1846.        if (aliens[index].z<(GAME_MIN_WORLD_Z-750))
  1847.            aliens[index].z=(GAME_MAX_WORLD_Z+500);
  1848.  
  1849.        } // end if alive
  1850.  
  1851.     } // end for index
  1852.  
  1853. // try and turn on dead guys at teleporters 10% chance
  1854.  
  1855. if ((rand()%10)==1)
  1856.    for (index=0; index<NUM_ALIENS; index++)
  1857.        {
  1858.        // test if this one is dead
  1859.  
  1860.        if (aliens[index].state==ALIEN_DEAD)
  1861.           {
  1862.  
  1863.           // set state to new state
  1864.  
  1865.           aliens[index].state = ALIEN_NEW_STATE;
  1866.  
  1867.           // select telepod position to start at
  1868.  
  1869.           which_pod = rand()%NUM_TELEPODS;
  1870.  
  1871.           aliens[index].x = telepods[which_pod].x;
  1872.           aliens[index].z = telepods[which_pod].z;
  1873.  
  1874.           // that's enough for now!
  1875.  
  1876.           break;
  1877.  
  1878.           } // end if
  1879.  
  1880.        } // end for index
  1881.  
  1882. } // end Process_Aliens
  1883.  
  1884. //////////////////////////////////////////////////////////////////////////////
  1885.  
  1886. void Draw_Aliens(void)
  1887. {
  1888. // this function simply draws the aliens
  1889.  
  1890. int index,       // looping variable
  1891.     diff_angle;  // used to track anglular difference between virtual object
  1892.                  // and real object
  1893.  
  1894. // draw all the aliens (ya all four of them!)
  1895.  
  1896. for (index=0; index<NUM_ALIENS; index++)
  1897.     {
  1898.     // test if missile is alive before starting 3-D processing
  1899.  
  1900.     if (aliens[index].state!=ALIEN_DEAD)
  1901.        {
  1902.  
  1903.        // which kind of alien are we dealing with?
  1904.  
  1905.        if (aliens[index].type == ALIEN_TALLON)
  1906.           {
  1907.  
  1908.           dynamic_obj[TALLONS_TEMPLATE].world_pos.x = aliens[index].x;
  1909.           dynamic_obj[TALLONS_TEMPLATE].world_pos.y = aliens[index].y;
  1910.           dynamic_obj[TALLONS_TEMPLATE].world_pos.z = aliens[index].z;
  1911.  
  1912.           if (!Remove_Object(&dynamic_obj[TALLONS_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  1913.              {
  1914.  
  1915.              // rotate tallon model to proper direction for this copy of it
  1916.  
  1917.              // look in state field of model to determine current angle and then
  1918.              // compare it to the desired angle, compute the difference and
  1919.              // use the result as the rotation angle to rotate the model
  1920.              // into the proper orientation for this copy of it
  1921.  
  1922.              diff_angle = aliens[index].angular_heading -
  1923.                           dynamic_obj[TALLONS_TEMPLATE].state;
  1924.  
  1925.              // fix the sign of the angle
  1926.  
  1927.              if (diff_angle<0)
  1928.                  diff_angle+=360;
  1929.  
  1930.              // perform the rotation
  1931.  
  1932.              Rotate_Object(&dynamic_obj[TALLONS_TEMPLATE],0,diff_angle,0);
  1933.  
  1934.              // update object template with new heading
  1935.  
  1936.              dynamic_obj[TALLONS_TEMPLATE].state = aliens[index].angular_heading;
  1937.  
  1938.              // convert object local coordinates to world coordinate
  1939.  
  1940.              Local_To_World_Object(&dynamic_obj[TALLONS_TEMPLATE]);
  1941.  
  1942.              // remove the backfaces and shade object
  1943.  
  1944.              if (aliens[index].state==ALIEN_DYING)
  1945.                  Remove_Backfaces_And_Shade(&dynamic_obj[TALLONS_TEMPLATE],aliens[index].color_reg);
  1946.              else
  1947.                  Remove_Backfaces_And_Shade(&dynamic_obj[TALLONS_TEMPLATE],-1);
  1948.  
  1949.              // convert world coordinates to camera coordinate
  1950.  
  1951.              World_To_Camera_Object(&dynamic_obj[TALLONS_TEMPLATE]);
  1952.  
  1953.              // clip the objects polygons against viewing volume
  1954.  
  1955.              Clip_Object_3D(&dynamic_obj[TALLONS_TEMPLATE],CLIP_Z_MODE);
  1956.  
  1957.              // generate the final polygon list
  1958.  
  1959.              Generate_Poly_List(&dynamic_obj[TALLONS_TEMPLATE],ADD_TO_POLY_LIST);
  1960.  
  1961.              } // end if object is outside viewing volume
  1962.  
  1963.           } // end if tallon
  1964.        else
  1965.           {
  1966.  
  1967.           dynamic_obj[SLIDERS_TEMPLATE].world_pos.x = aliens[index].x;
  1968.           dynamic_obj[SLIDERS_TEMPLATE].world_pos.y = aliens[index].y;
  1969.           dynamic_obj[SLIDERS_TEMPLATE].world_pos.z = aliens[index].z;
  1970.  
  1971.           if (!Remove_Object(&dynamic_obj[SLIDERS_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  1972.              {
  1973.  
  1974.              // rotate slider model to proper direction for this copy of it
  1975.  
  1976.              // look in state field of model to determine current angle and then
  1977.              // compare it to the desired angle, compute the difference and
  1978.              // use the result as the rotation angle to rotate the model
  1979.              // into the proper orientation for this copy of it
  1980.  
  1981.              diff_angle = aliens[index].angular_heading -
  1982.                           dynamic_obj[SLIDERS_TEMPLATE].state;
  1983.  
  1984.              // fix the sign of the angle
  1985.  
  1986.              if (diff_angle<0)
  1987.                  diff_angle+=360;
  1988.  
  1989.              // perform the rotation
  1990.  
  1991.              Rotate_Object(&dynamic_obj[SLIDERS_TEMPLATE],0,diff_angle,0);
  1992.  
  1993.              // update object template with new heading
  1994.  
  1995.              dynamic_obj[SLIDERS_TEMPLATE].state = aliens[index].angular_heading;
  1996.  
  1997.              // convert object local coordinates to world coordinate
  1998.  
  1999.              Local_To_World_Object(&dynamic_obj[SLIDERS_TEMPLATE]);
  2000.  
  2001.              // remove the backfaces and shade object
  2002.  
  2003.              if (aliens[index].state==ALIEN_DYING)
  2004.                  Remove_Backfaces_And_Shade(&dynamic_obj[SLIDERS_TEMPLATE],aliens[index].color_reg);
  2005.              else
  2006.                  Remove_Backfaces_And_Shade(&dynamic_obj[SLIDERS_TEMPLATE],-1);
  2007.  
  2008.              // convert world coordinates to camera coordinate
  2009.  
  2010.              World_To_Camera_Object(&dynamic_obj[SLIDERS_TEMPLATE]);
  2011.  
  2012.              // clip the objects polygons against viewing volume
  2013.  
  2014.              Clip_Object_3D(&dynamic_obj[SLIDERS_TEMPLATE],CLIP_Z_MODE);
  2015.  
  2016.              // generate the final polygon list
  2017.  
  2018.              Generate_Poly_List(&dynamic_obj[SLIDERS_TEMPLATE],ADD_TO_POLY_LIST);
  2019.  
  2020.              } // end if object is outside viewing volume
  2021.  
  2022.           } // end else slider
  2023.  
  2024.        } // end if alien alive
  2025.  
  2026.     } // end for index
  2027.  
  2028. } // end Draw_Aliens
  2029.  
  2030. /////////////////////////////////////////////////////////////////////////////
  2031.  
  2032. void Draw_Background(int mountain_pos)
  2033. {
  2034. // this function draw the gradient sky and ground for the 3-D view
  2035.  
  2036. long color; // used to build up a 4 byte color
  2037.  
  2038. // this function draws the background and mountains for the foreground
  2039. // 3-D image
  2040.  
  2041. // the sky has three layers
  2042.  
  2043. // draw layer 1
  2044.  
  2045. color = SKY_COLOR_1;
  2046.  
  2047. color = color | (color << 8);
  2048. color = color | (color << 16);
  2049.  
  2050. fquadset(double_buffer, color, 4*320/4);
  2051.  
  2052. // draw layer 2
  2053.  
  2054. color = SKY_COLOR_2;
  2055.  
  2056. color = color | (color << 8);
  2057. color = color | (color << 16);
  2058.  
  2059. fquadset(double_buffer+320*4, color, 8*320/4);
  2060.  
  2061. // draw layer 3
  2062.  
  2063. color = SKY_COLOR_3;
  2064.  
  2065. color = color | (color << 8);
  2066. color = color | (color << 16);
  2067.  
  2068. fquadset(double_buffer+320*12, color, 44*320/4);
  2069.  
  2070. // now draw the scrolling mountainscape
  2071.  
  2072. Layer_Draw((layer_ptr)&mountains,mountain_pos,0,
  2073.            double_buffer,MOUNTAIN_Y_POS,MOUNTAIN_HEIGHT,0);
  2074.  
  2075. // now draw the ground
  2076.  
  2077. // layer 1
  2078.  
  2079. color = GND_COLOR_1;
  2080.  
  2081. color = color | (color << 8);
  2082. color = color | (color << 16);
  2083.  
  2084. fquadset(double_buffer+320*99, color, 3*320/4);
  2085.  
  2086. // layer 2
  2087.  
  2088. color = GND_COLOR_2;
  2089.  
  2090. color = color | (color << 8);
  2091. color = color | (color << 16);
  2092.  
  2093. fquadset(double_buffer+320*102, color, 6*320/4);
  2094.  
  2095. color = GND_COLOR_3;
  2096.  
  2097. color = color | (color << 8);
  2098. color = color | (color << 16);
  2099.  
  2100. fquadset(double_buffer+320*108, color, 21*320/4);
  2101.  
  2102. } // end Draw_Background
  2103.  
  2104. /////////////////////////////////////////////////////////////////////////////
  2105.  
  2106. void Draw_Box(int x1,int y1,int x2, int y2,int color)
  2107. {
  2108. // this function draws a hollow rectangle
  2109.  
  2110. Line_H(x1,x2,y1,color);
  2111. Line_H(x1,x2,y2,color);
  2112. Line_V(y1,y2,x1,color);
  2113. Line_V(y1,y2,x2,color);
  2114.  
  2115. } // end Draw_Box
  2116.  
  2117. ///////////////////////////////////////////////////////////////////////////////
  2118.  
  2119. void Tech_Print(int x,int y,char *string,unsigned char far *destination)
  2120. {
  2121. // this function is used to print text out like a teletypwriter,it looks
  2122. // cool, trust me!
  2123.  
  2124. int length,  // length of input string
  2125.     index,   // looping variable
  2126.     counter; // used to time process
  2127.  
  2128. char buffer[3];  // a little string used to call font engine with
  2129.  
  2130. // compute length of input string
  2131.  
  2132. length = strlen(string);
  2133.  
  2134. // print the string out a character at a time
  2135.  
  2136. for (index=0; index<length; index++)
  2137.     {
  2138.     // the first character is the actual printable character
  2139.  
  2140.     buffer[0] = string[index];
  2141.  
  2142.     // null terminate
  2143.  
  2144.     buffer[1] = 0;
  2145.  
  2146.     // print the string
  2147.  
  2148.     Font_Engine_1(x,y,0,0,buffer,destination);
  2149.  
  2150.     // move to next position
  2151.  
  2152.     x+=(TECH_FONT_WIDTH+1);
  2153.  
  2154.     // wait a bit  1/70th of a second
  2155.  
  2156.     Wait_For_Vertical_Retrace();
  2157.  
  2158.     // clear the cursor
  2159.  
  2160.     } // end for
  2161.  
  2162. // done!
  2163.  
  2164. } // end Tech_Print
  2165.  
  2166. //////////////////////////////////////////////////////////////////////////////
  2167.  
  2168. void Font_Engine_1(int x,int y,
  2169.                    int font,int color,
  2170.                    char *string,unsigned char far *destination)
  2171. {
  2172. // this function prints a string out using one of the graphics fonts that
  2173. // we have drawn, note this first version doesn't use the font field, but
  2174. // we'll throw it in to keep the interface open for a future version
  2175.  
  2176. static int font_loaded=0;   // this is used to track the first time the
  2177.                             // function is loaded
  2178.  
  2179. int index,    // loop index
  2180.     c_index,  // character index
  2181.     length;   // used to compute lengths of strings
  2182.  
  2183. // test if this is the first time this function is called, if so load the
  2184. // font
  2185.  
  2186. if (!font_loaded)
  2187.    {
  2188.    // load the 4x7 tech font
  2189.  
  2190.    PCX_Init((pcx_picture_ptr)&image_pcx);
  2191.    PCX_Load("krkfnt.pcx", (pcx_picture_ptr)&image_pcx,1);
  2192.  
  2193.    // allocate memory for each bitmap and load character
  2194.  
  2195.    for (index=0; index<NUM_TECH_FONT; index++)
  2196.        {
  2197.        // allocate memory for charcter
  2198.  
  2199.        Bitmap_Allocate((bitmap_ptr)&tech_font[index],
  2200.                        TECH_FONT_WIDTH,TECH_FONT_HEIGHT);
  2201.  
  2202.        // set size of character
  2203.  
  2204.        tech_font[index].width = TECH_FONT_WIDTH;
  2205.        tech_font[index].height= TECH_FONT_HEIGHT;
  2206.  
  2207.        // extract bitmap from PCX buffer
  2208.  
  2209.        tech_font[index].x = 1 + (index % 16) * (TECH_FONT_WIDTH+1);
  2210.        tech_font[index].y = 1 + (index / 16) * (TECH_FONT_HEIGHT+1);
  2211.  
  2212.        Bitmap_Get((bitmap_ptr)&tech_font[index],
  2213.                   (unsigned char far *)image_pcx.buffer);
  2214.  
  2215.        } // end for index
  2216.    // font is loaded, delete pcx file and set flag
  2217.  
  2218.    PCX_Delete((pcx_picture_ptr)&image_pcx);
  2219.  
  2220.    font_loaded=1;
  2221.  
  2222.    } // end if first time
  2223. else
  2224.    {
  2225.    // print the sent string
  2226.  
  2227.    // pre-compute length of string
  2228.  
  2229.    length=strlen(string);
  2230.  
  2231.    // print the string character by character
  2232.  
  2233.    for (index=0; index<length; index++)
  2234.        {
  2235.        // extract the character index from the space character
  2236.  
  2237.        c_index = string[index] - ' ';
  2238.  
  2239.        // set bitmap position
  2240.  
  2241.        tech_font[c_index].y = y;
  2242.        tech_font[c_index].x = x;
  2243.  
  2244.        // display bitmap
  2245.  
  2246.        Bitmap_Put((bitmap_ptr)&tech_font[c_index],
  2247.                   (unsigned char far*)destination,0);
  2248.  
  2249.        // move to next character position
  2250.  
  2251.        x+=(TECH_FONT_WIDTH+1);
  2252.  
  2253.        } // end for index
  2254.  
  2255.    } // end else print string
  2256.  
  2257. } // end Font_Engine_1
  2258.  
  2259. /////////////////////////////////////////////////////////////////////////////
  2260.  
  2261. void Panel_FX(int reset)
  2262. {
  2263. // this function performs all of the special effects for the control panel
  2264.  
  2265. int index; // looping variable
  2266.  
  2267. static int panel_counter = 0;  // used to time the color rotation of the panel
  2268.  
  2269. static int entered=0; // flags if function has been entered yet
  2270.  
  2271. // test if this is the first time in function
  2272.  
  2273. if (!entered || reset)
  2274.    {
  2275.    // set entrance flag
  2276.  
  2277.    entered = 1;
  2278.  
  2279.    // set up color registers
  2280.  
  2281.    for (index=START_PANEL_REG; index<=END_PANEL_REG; index++)
  2282.        {
  2283.        // generate the color
  2284.  
  2285.        color_1.red   = 0;
  2286.        color_1.green = 0;
  2287.        color_1.blue  = 0;
  2288.  
  2289.        // write the data
  2290.  
  2291.        Write_Color_Reg(index, (RGB_color_ptr)&color_1);
  2292.  
  2293.        } // end for
  2294.  
  2295.    color_1.red   = 63;
  2296.  
  2297.    Write_Color_Reg(START_PANEL_REG,(RGB_color_ptr)&color_1);
  2298.  
  2299.    Write_Color_Reg(START_PANEL_REG+3,(RGB_color_ptr)&color_1);
  2300.  
  2301.    // set up selection indicator color
  2302.  
  2303.    color_1.red   = 30;
  2304.    color_1.green = 0;
  2305.    color_1.blue  = 0;
  2306.  
  2307.    Write_Color_Reg(SELECT_REG, (RGB_color_ptr)&color_1);
  2308.  
  2309.    } // end if entered
  2310.  
  2311. // is it time to update colors?
  2312.  
  2313. if (++panel_counter>2)
  2314.    {
  2315.    // reset counter
  2316.  
  2317.    panel_counter=0;
  2318.  
  2319.    // do animation to colors
  2320.  
  2321.    Read_Color_Reg(END_PANEL_REG, (RGB_color_ptr)&color_1);
  2322.  
  2323.    for (index=END_PANEL_REG; index>START_PANEL_REG; index--)
  2324.        {
  2325.        // read the (i-1)th register
  2326.  
  2327.        Read_Color_Reg(index-1, (RGB_color_ptr)&color_2);
  2328.  
  2329.        // assign it to the ith
  2330.  
  2331.        Write_Color_Reg(index, (RGB_color_ptr)&color_2);
  2332.  
  2333.        } // end rotate loop
  2334.  
  2335.     // place the value of the first color register into the last to
  2336.     // complete the rotation
  2337.  
  2338.     Write_Color_Reg(START_PANEL_REG, (RGB_color_ptr)&color_1);
  2339.  
  2340.    } // end if time
  2341.  
  2342. // update selection color
  2343.  
  2344. Read_Color_Reg(SELECT_REG, (RGB_color_ptr)&color_1);
  2345.  
  2346. if ((color_1.red+=5) > 63)
  2347.    color_1.red = 25;
  2348.  
  2349. Write_Color_Reg(SELECT_REG, (RGB_color_ptr)&color_1);
  2350.  
  2351. } // end Panel_FX
  2352.  
  2353. /////////////////////////////////////////////////////////////////////////////
  2354.  
  2355. void Intro_Planet(void)
  2356. {
  2357. // this function does the introdcution to centari alpha 3
  2358.  
  2359. int index; // looping variable
  2360.  
  2361. // data output fields
  2362.  
  2363. static char *template[]={"PLANET:   ",
  2364.                          "TYPE:     ",
  2365.                          "MASS:     ",
  2366.                          "TEMP:     ",
  2367.                          "PERIOD:   ",
  2368.                          "LIFEFORMS:",
  2369.                          "STATUS:   ",};
  2370.  
  2371. // the data for each field
  2372.  
  2373. static char *data[] = {" CENTARI ALPHA 3",
  2374.                        " F-CLASS, AMMONIUM ATMOSPHERE",
  2375.                        " 20.6 KELA",
  2376.                        " 150.2 DEG",
  2377.                        " 3.2 TELGANS",
  2378.                        " SILICA BASED, PHOSPOROUS METABOLIZERS",
  2379.                        " BATTLE AREA - RESTRICTED" };
  2380.  
  2381. // load in the KRK title screen
  2382.  
  2383. PCX_Init((pcx_picture_ptr)&image_pcx);
  2384. PCX_Load("krkredp.pcx",(pcx_picture_ptr)&image_pcx,1);
  2385.  
  2386. // show the PCX buffer
  2387.  
  2388. PCX_Show_Buffer((pcx_picture_ptr)&image_pcx);
  2389.  
  2390. // done with data so delete it
  2391.  
  2392. PCX_Delete((pcx_picture_ptr)&image_pcx);
  2393.  
  2394. // do special effects
  2395.  
  2396. Time_Delay(50);
  2397.  
  2398. // draw out statistics
  2399.  
  2400. for (index=0; index<7; index++)
  2401.     {
  2402.  
  2403.     // draw header field
  2404.  
  2405.     Font_Engine_1(START_MESS_X,START_MESS_Y+index*10,0,0,
  2406.                   template[index],
  2407.                   video_buffer);
  2408.  
  2409.  
  2410.     // draw information for field
  2411.  
  2412.     Tech_Print(START_MESS_X+80,START_MESS_Y+index*10,data[index],video_buffer);
  2413.  
  2414.     Time_Delay(20);
  2415.  
  2416.     } // end for index
  2417.  
  2418. // wait for a sec
  2419.  
  2420. Time_Delay(50);
  2421.  
  2422. } // end Intro_Planet
  2423.  
  2424. //////////////////////////////////////////////////////////////////////////////
  2425.  
  2426. void Closing_Screen(void)
  2427. {
  2428. // this function prints the credits
  2429.  
  2430. int index;  // looping variable
  2431.  
  2432. static char *extra_credits[] = {"EXTRA CREDITS",
  2433.                                 "             ",
  2434.                                 "MUSICAL MASTERY BY",
  2435.                                 "DEAN HUDSON OF",
  2436.                                 "ECLIPSE PRODUCTIONS",
  2437.                                 "                   ",
  2438.                                 "MIDPAK INSTRUMENTATION CONSULTING BY",
  2439.                                 "ROB WALLACE OF",
  2440.                                 "WALLACE MUSIC & SOUND",
  2441.                                 "                     ",
  2442.                                 "TITLE SCREEN BY",
  2443.                                 "RICHARD BENSON"};
  2444.  
  2445. // blank the screen
  2446.  
  2447. Fill_Screen(0);
  2448.  
  2449. // restore pallete
  2450.  
  2451. Write_Palette(0,255,(RGB_palette_ptr)&game_palette);
  2452.  
  2453. if (music_enabled)
  2454.    {
  2455.    Music_Stop();
  2456.    Music_Play((music_ptr)&song,11);
  2457.    } // end if
  2458.  
  2459. // print out the credits
  2460.  
  2461. for (index=0; index<=11; index++)
  2462.     {
  2463.  
  2464.     Tech_Print(160-(TECH_FONT_WIDTH+1)*(strlen(extra_credits[index])/2),
  2465.                8+index*(TECH_FONT_HEIGHT+4),
  2466.                extra_credits[index],video_buffer);
  2467.  
  2468.     if (keys_active)
  2469.        return;
  2470.  
  2471.     Time_Delay(10);
  2472.  
  2473.     } // end for index
  2474.  
  2475. Time_Delay(50);
  2476.  
  2477. // scroll them away
  2478.  
  2479. for (index=0; index<135; index++)
  2480.     {
  2481.     fquadcpy(video_buffer,video_buffer+320,16000-80);
  2482.  
  2483.     // test for exit
  2484.  
  2485.     if (keys_active)
  2486.        return;
  2487.  
  2488.     } // end for index
  2489.  
  2490. } // end Closing_Screen
  2491.  
  2492. //////////////////////////////////////////////////////////////////////////////
  2493.  
  2494. void Intro_Waite(void)
  2495. {
  2496. // load in the waite group title screen
  2497.  
  2498. PCX_Init((pcx_picture_ptr)&image_pcx);
  2499. PCX_Load("waite.pcx",(pcx_picture_ptr)&image_pcx,1);
  2500.  
  2501. // done with data so delete it
  2502.  
  2503. PCX_Delete((pcx_picture_ptr)&image_pcx);
  2504.  
  2505. // show the PCX buffer
  2506.  
  2507. PCX_Show_Buffer((pcx_picture_ptr)&image_pcx);
  2508.  
  2509. // do special effects
  2510.  
  2511. // wait for a sec
  2512.  
  2513. Time_Delay(40);
  2514.  
  2515. Screen_Transition(SCREEN_WHITENESS);
  2516.  
  2517. // blank the screen
  2518.  
  2519. Fill_Screen(0);
  2520.  
  2521. } // end Intro_Waite
  2522.  
  2523. //////////////////////////////////////////////////////////////////////////////
  2524.  
  2525. void Intro_KRK(void)
  2526. {
  2527. // load in the main title screen group title screen
  2528.  
  2529. PCX_Init((pcx_picture_ptr)&image_pcx);
  2530. PCX_Load("krkfirst.pcx",(pcx_picture_ptr)&image_pcx,1);
  2531.  
  2532. // done with data so delete it
  2533.  
  2534. PCX_Delete((pcx_picture_ptr)&image_pcx);
  2535.  
  2536. // show the PCX buffer
  2537.  
  2538. PCX_Show_Buffer((pcx_picture_ptr)&image_pcx);
  2539.  
  2540. // do special effects
  2541.  
  2542. // wait for a sec
  2543.  
  2544. Time_Delay(50);
  2545.  
  2546. Screen_Transition(SCREEN_DARKNESS);
  2547.  
  2548. // blank the screen
  2549.  
  2550. Fill_Screen(0);
  2551.  
  2552. } // end Intro_KRK
  2553.  
  2554. //////////////////////////////////////////////////////////////////////////////
  2555.  
  2556. void Intro_Controls(void)
  2557. {
  2558. // this function displays the controls screen
  2559.  
  2560. // load in the starblazer controls screen
  2561.  
  2562. PCX_Init((pcx_picture_ptr)&image_controls);
  2563. PCX_Load("krkredpc.pcx",(pcx_picture_ptr)&image_controls,1);
  2564.  
  2565. // copy controls data to video buffer
  2566.  
  2567. PCX_Show_Buffer((pcx_picture_ptr)&image_controls);
  2568.  
  2569. // delete pcx file
  2570.  
  2571. PCX_Delete((pcx_picture_ptr)&image_controls);
  2572.  
  2573. } // end Intro_Controls
  2574.  
  2575. ////////////////////////////////////////////////////////////////////////////
  2576.  
  2577. void Intro_Briefing(void)
  2578. {
  2579. // this function displays the briefing screen
  2580.  
  2581. int done=0, // exit flag
  2582.     page=0, // current page user is reading
  2583.     index;  // looping variable
  2584.  
  2585. // load in the starblazer controls screen
  2586.  
  2587. PCX_Init((pcx_picture_ptr)&image_controls);
  2588. PCX_Load("krkins.pcx",(pcx_picture_ptr)&image_controls,0);
  2589.  
  2590. // copy controls data to video buffer
  2591.  
  2592. PCX_Show_Buffer((pcx_picture_ptr)&image_controls);
  2593.  
  2594. // delete pcx file
  2595.  
  2596. PCX_Delete((pcx_picture_ptr)&image_controls);
  2597.  
  2598. // display the first page
  2599.  
  2600. for (index=0; index<NUM_LINES_PAGE; index++)
  2601.     Font_Engine_1(78,24+index*8,0,0,instructions[index+page*17],video_buffer);
  2602.  
  2603. // enter main event loop
  2604.  
  2605. while(!done)
  2606.      {
  2607.      // has the user pressed a key
  2608.  
  2609.      if (keys_active>0)
  2610.         {
  2611.  
  2612.         if (keyboard_state[MAKE_UP])
  2613.            {
  2614.            // page up
  2615.  
  2616.            if (--page<0)
  2617.               page = 0;
  2618.  
  2619.            // press button
  2620.  
  2621.            Digital_FX_Play(KRKKEY_VOC,3);
  2622.  
  2623.            Time_Delay(2);
  2624.  
  2625.            } // end if up
  2626.  
  2627.         if (keyboard_state[MAKE_DOWN])
  2628.            {
  2629.            // page down
  2630.  
  2631.            if (++page>=NUM_PAGES)
  2632.               page = NUM_PAGES-1;
  2633.  
  2634.            // press button
  2635.  
  2636.            Digital_FX_Play(KRKKEY_VOC,3);
  2637.  
  2638.            Time_Delay(2);
  2639.  
  2640.            } // end if down
  2641.  
  2642.         if (keyboard_state[MAKE_ESC])
  2643.            {
  2644.  
  2645.            Digital_FX_Play(KRKKEY_VOC,3);
  2646.  
  2647.            done=1;
  2648.  
  2649.            } // end if esc
  2650.  
  2651.         // refresh display
  2652.  
  2653.         for (index=0; index<NUM_LINES_PAGE; index++)
  2654.             Font_Engine_1(78,24+index*8,0,0,instructions[index+page*17],video_buffer);
  2655.  
  2656.         } // end if a key has been pressed
  2657.  
  2658.      // wait a sec
  2659.  
  2660.      Time_Delay(1);
  2661.  
  2662.      // check on music
  2663.  
  2664.      if (music_enabled)
  2665.         {
  2666.         // test if piece is complete or has been stopped
  2667.  
  2668.         if (Music_Status()==2 || Music_Status()==0)
  2669.            {
  2670.            // advance to next sequence
  2671.  
  2672.            if (++intro_seq_index==14)
  2673.               intro_seq_index=0;
  2674.  
  2675.            Music_Play((music_ptr)&song,intro_sequence[intro_seq_index]);
  2676.  
  2677.            } // end if
  2678.  
  2679.         } // end if music enabled
  2680.  
  2681.      } // end main while
  2682.  
  2683. } // end Intro_Briefing
  2684.  
  2685. //////////////////////////////////////////////////////////////////////////////
  2686.  
  2687. void Reset_System(void)
  2688. {
  2689. // this function resets everything so the game can be ran again
  2690. // I hope I didn't leave anything out?
  2691.  
  2692. scanner_state  = 0;
  2693. hud_state      = 0;
  2694. tactical_state = TACTICAL_MODE_OFF;
  2695.  
  2696. ship_pitch     = 0;
  2697. ship_yaw       = 0;
  2698. ship_roll      = 0;
  2699. ship_speed     = 0;
  2700. ship_energy    = 50;
  2701. ship_damage    = 0;
  2702. ship_message   = SHIP_STABLE;
  2703. ship_timer     = 0;
  2704. ship_kills     = 0;
  2705. ship_deaths    = 0;
  2706.  
  2707. // reset back to power station
  2708.  
  2709. view_point.x = 0;
  2710. view_point.z = 0;
  2711.  
  2712. } // end Reset_System
  2713.  
  2714. /////////////////////////////////////////////////////////////////////////////
  2715.  
  2716. void Music_Init(void)
  2717. {
  2718. // this function loads the music and resets all the indexes
  2719.  
  2720. static int loaded=0;
  2721.  
  2722. // has the music already been loaded
  2723.  
  2724. if (!music_enabled)
  2725.    return;
  2726.  
  2727. if (!loaded)
  2728.    {
  2729.    Music_Load("krkmus.xmi",(music_ptr)&song);
  2730.    loaded=1;
  2731.    } // end if not loaded
  2732.  
  2733. // reset sequence counters
  2734.  
  2735. game_seq_index=0;
  2736. intro_seq_index=0;
  2737.  
  2738. } // end Music_Init
  2739.  
  2740. /////////////////////////////////////////////////////////////////////////////
  2741.  
  2742. void Music_Close(void)
  2743. {
  2744. // this function unloads the music files
  2745.  
  2746. if (!music_enabled)
  2747.    return;
  2748.  
  2749. // turn off music and unload song
  2750.  
  2751. Music_Stop();
  2752. Music_Unload((music_ptr)&song);
  2753.  
  2754. } // end Music_Close
  2755.  
  2756. //////////////////////////////////////////////////////////////////////////////
  2757.  
  2758. void Digital_FX_Init(void)
  2759. {
  2760. // this function initializes the digital sound fx system
  2761.  
  2762. static int loaded=0;
  2763.  
  2764. if (!digital_enabled)
  2765.    return;
  2766.  
  2767. // have the sound fx been loaded?
  2768.  
  2769. if (!loaded)
  2770.    {
  2771.     // load int sounds
  2772.  
  2773.     Sound_Load("KRKMIS.VOC" ,  (_sound_ptr)&digital_FX[KRKMIS_VOC ] ,1);
  2774.     Sound_Load("KRKEMIS2.VOC", (_sound_ptr)&digital_FX[KRKEMIS_VOC],1);
  2775.     Sound_Load("KRKTAC.VOC" ,  (_sound_ptr)&digital_FX[KRKTAC_VOC ],1);
  2776.     Sound_Load("KRKSCN.VOC" ,  (_sound_ptr)&digital_FX[KRKSCN_VOC ],1);
  2777.    Sound_Load("KRKHUD.VOC" ,  (_sound_ptr)&digital_FX[KRKHUD_VOC ],1);
  2778.  
  2779.    Sound_Load("KRKKEY.VOC" ,  (_sound_ptr)&digital_FX[KRKKEY_VOC ],1);
  2780.    Sound_Load("KRKEX1.VOC" ,  (_sound_ptr)&digital_FX[KRKEX1_VOC ],1);
  2781.    Sound_Load("KRKEX2.VOC" ,  (_sound_ptr)&digital_FX[KRKEX2_VOC ],1);
  2782.  
  2783.    // set loaded flag
  2784.  
  2785.    loaded=1;
  2786.  
  2787.    } // end if sound effects aren't loaded
  2788.  
  2789. } // end Digital_FX_Init
  2790.  
  2791. ///////////////////////////////////////////////////////////////////////////////
  2792.  
  2793. void Digital_FX_Close(void)
  2794. {
  2795. // this function unloads all the digital FX
  2796.  
  2797. if (!digital_enabled)
  2798.    return;
  2799.  
  2800. // unload all the sound fx from memory
  2801.  
  2802. Sound_Unload((_sound_ptr)&digital_FX[KRKMIS_VOC]);
  2803. Sound_Unload((_sound_ptr)&digital_FX[KRKEMIS_VOC]);
  2804. Sound_Unload((_sound_ptr)&digital_FX[KRKTAC_VOC]);
  2805. Sound_Unload((_sound_ptr)&digital_FX[KRKSCN_VOC]);
  2806. Sound_Unload((_sound_ptr)&digital_FX[KRKHUD_VOC]);
  2807.  
  2808. Sound_Unload((_sound_ptr)&digital_FX[KRKPOW_VOC]);
  2809. Sound_Unload((_sound_ptr)&digital_FX[KRKKEY_VOC]);
  2810. Sound_Unload((_sound_ptr)&digital_FX[KRKEX1_VOC]);
  2811. Sound_Unload((_sound_ptr)&digital_FX[KRKEX2_VOC]);
  2812.  
  2813. } // end Digital_FX_Close
  2814.  
  2815. /////////////////////////////////////////////////////////////////////////////
  2816.  
  2817. int Digital_FX_Play(int the_effect, int priority)
  2818. {
  2819. // this function is used to play a digital effect using a pre-emptive priority
  2820. // scheme. The algorithm works like this: if a sound is playing then its
  2821. // priority is compared to the sound that is being requested to be played
  2822. // if the new sound has higher priority (a smaller number) then the currenlty
  2823. // playing sound is pre-empted for the new sound and the global FX priority
  2824. // is set to the new sound. If there is no sound playing then the new sound
  2825. // is simple played and the global priority is set
  2826.  
  2827. // is the digital fx system on-line?
  2828.  
  2829. if (!digital_enabled)
  2830.    return(0);
  2831.  
  2832. // is there a sound playing?
  2833.  
  2834. if (!Sound_Status() || (priority <= digital_FX_priority))
  2835.    {
  2836.    // start new sound
  2837.  
  2838.    Sound_Stop();
  2839.  
  2840.     Sound_Play((_sound_ptr)&digital_FX[the_effect]);
  2841.  
  2842.    // set the priority
  2843.  
  2844.    digital_FX_priority = priority;
  2845.  
  2846.    return(1);
  2847.  
  2848.    } // end if
  2849. else // the current sound is of higher priority
  2850.    return(0);
  2851.  
  2852. } // end Digital_FX_Play
  2853.  
  2854. /////////////////////////////////////////////////////////////////////////////
  2855.  
  2856. int Parse_Commands(int argc, char **argv)
  2857. {
  2858. // this function is used to parse the commands line parameters that are to be
  2859. // used as switched to enable different modes of operation
  2860.  
  2861. int index;  // looping variable
  2862.  
  2863. for (index=1; index<argc; index++)
  2864.     {
  2865.     // get the first character from the string
  2866.  
  2867.     switch(argv[index][0])
  2868.           {
  2869.  
  2870.           case 's': // enable sound effects
  2871.           case 'S':
  2872.                {
  2873.                digital_enabled=1;
  2874.                } break;
  2875.  
  2876.           case 'm': // enable nusic
  2877.           case 'M':
  2878.                {
  2879.                music_enabled=1;
  2880.                } break;
  2881.  
  2882.           // more commands would go here...
  2883.  
  2884.           default:break;
  2885.  
  2886.           } // end switch
  2887.  
  2888.     } // end for index
  2889.  
  2890. } // end Parse_Commands
  2891.  
  2892. ////////////////////////////////////////////////////////////////////////////
  2893.  
  2894. void Draw_Stationary_Objects(void)
  2895. {
  2896. // this function draws all the stationary non active objects
  2897.  
  2898. int index; // looping index
  2899.  
  2900. // phase 0: obstacle type one
  2901.  
  2902. for (index=0; index<NUM_OBSTACLES_1; index++)
  2903.     {
  2904.     // test if object is visible
  2905.  
  2906.     // now before we continue to process object, we must
  2907.     // move it to the proper world position
  2908.  
  2909.     static_obj[OBSTACLES_1_TEMPLATE].world_pos.x = obstacles_1[index].x;
  2910.     static_obj[OBSTACLES_1_TEMPLATE].world_pos.y = obstacles_1[index].y;
  2911.     static_obj[OBSTACLES_1_TEMPLATE].world_pos.z = obstacles_1[index].z;
  2912.  
  2913.     if (!Remove_Object(&static_obj[OBSTACLES_1_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  2914.        {
  2915.  
  2916.        // convert object local coordinates to world coordinate
  2917.  
  2918.        Local_To_World_Object(&static_obj[OBSTACLES_1_TEMPLATE]);
  2919.  
  2920.        // remove the backfaces and shade object
  2921.  
  2922.        Remove_Backfaces_And_Shade(&static_obj[OBSTACLES_1_TEMPLATE],-1);
  2923.  
  2924.        // convert world coordinates to camera coordinate
  2925.  
  2926.        World_To_Camera_Object(&static_obj[OBSTACLES_1_TEMPLATE]);
  2927.  
  2928.        // clip the objects polygons against viewing volume
  2929.  
  2930.        Clip_Object_3D(&static_obj[OBSTACLES_1_TEMPLATE],CLIP_Z_MODE);
  2931.  
  2932.        // generate the final polygon list
  2933.  
  2934.        Generate_Poly_List(&static_obj[OBSTACLES_1_TEMPLATE],ADD_TO_POLY_LIST);
  2935.        }
  2936.  
  2937.     }  // end for index
  2938.  
  2939. // phase 1: obstacle type two
  2940.  
  2941. for (index=0; index<NUM_OBSTACLES_2; index++)
  2942.     {
  2943.     // test if object is visible
  2944.  
  2945.     // now before we continue to process object, we must
  2946.     // move it to the proper world position
  2947.  
  2948.     static_obj[OBSTACLES_2_TEMPLATE].world_pos.x = obstacles_2[index].x;
  2949.     static_obj[OBSTACLES_2_TEMPLATE].world_pos.y = obstacles_2[index].y;
  2950.     static_obj[OBSTACLES_2_TEMPLATE].world_pos.z = obstacles_2[index].z;
  2951.  
  2952.     if (!Remove_Object(&static_obj[OBSTACLES_2_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  2953.        {
  2954.  
  2955.        // convert object local coordinates to world coordinate
  2956.  
  2957.        Local_To_World_Object(&static_obj[OBSTACLES_2_TEMPLATE]);
  2958.  
  2959.        // remove the backfaces and shade object
  2960.  
  2961.        Remove_Backfaces_And_Shade(&static_obj[OBSTACLES_2_TEMPLATE],-1);
  2962.  
  2963.        // convert world coordinates to camera coordinate
  2964.  
  2965.        World_To_Camera_Object(&static_obj[OBSTACLES_2_TEMPLATE]);
  2966.  
  2967.        // clip the objects polygons against viewing volume
  2968.  
  2969.        Clip_Object_3D(&static_obj[OBSTACLES_2_TEMPLATE],CLIP_Z_MODE);
  2970.  
  2971.        // generate the final polygon list
  2972.  
  2973.        Generate_Poly_List(&static_obj[OBSTACLES_2_TEMPLATE],ADD_TO_POLY_LIST);
  2974.        }
  2975.  
  2976.     }  // end for index
  2977.  
  2978. // phase 2: the towers
  2979.  
  2980. for (index=0; index<NUM_TOWERS; index++)
  2981.     {
  2982.     // test if object is visible
  2983.  
  2984.     // now before we continue to process object, we must
  2985.     // move it to the proper world position
  2986.  
  2987.     static_obj[TOWERS_TEMPLATE].world_pos.x = towers[index].x;
  2988.     static_obj[TOWERS_TEMPLATE].world_pos.y = towers[index].y;
  2989.     static_obj[TOWERS_TEMPLATE].world_pos.z = towers[index].z;
  2990.  
  2991.     if (!Remove_Object(&static_obj[TOWERS_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  2992.        {
  2993.  
  2994.        // convert object local coordinates to world coordinate
  2995.  
  2996.        Local_To_World_Object(&static_obj[TOWERS_TEMPLATE]);
  2997.  
  2998.        // remove the backfaces and shade object
  2999.  
  3000.        Remove_Backfaces_And_Shade(&static_obj[TOWERS_TEMPLATE],-1);
  3001.  
  3002.        // convert world coordinates to camera coordinate
  3003.  
  3004.        World_To_Camera_Object(&static_obj[TOWERS_TEMPLATE]);
  3005.  
  3006.        // clip the objects polygons against viewing volume
  3007.  
  3008.        Clip_Object_3D(&static_obj[TOWERS_TEMPLATE],CLIP_Z_MODE);
  3009.  
  3010.        // generate the final polygon list
  3011.  
  3012.        Generate_Poly_List(&static_obj[TOWERS_TEMPLATE],ADD_TO_POLY_LIST);
  3013.        }
  3014.  
  3015.     }  // end for index
  3016.  
  3017.  
  3018. // phase 3: the barriers
  3019.  
  3020. for (index=0; index<NUM_BARRIERS; index++)
  3021.     {
  3022.     // test if object is visible
  3023.  
  3024.     // now before we continue to process object, we must
  3025.     // move it to the proper world position
  3026.  
  3027.     static_obj[BARRIERS_TEMPLATE].world_pos.x = barriers[index].x;
  3028.     static_obj[BARRIERS_TEMPLATE].world_pos.y = barriers[index].y;
  3029.     static_obj[BARRIERS_TEMPLATE].world_pos.z = barriers[index].z;
  3030.  
  3031.     if (!Remove_Object(&static_obj[BARRIERS_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  3032.        {
  3033.  
  3034.        // convert object local coordinates to world coordinate
  3035.  
  3036.        Local_To_World_Object(&static_obj[BARRIERS_TEMPLATE]);
  3037.  
  3038.        // remove the backfaces and shade object
  3039.  
  3040.        Remove_Backfaces_And_Shade(&static_obj[BARRIERS_TEMPLATE],-1);
  3041.  
  3042.        // convert world coordinates to camera coordinate
  3043.  
  3044.        World_To_Camera_Object(&static_obj[BARRIERS_TEMPLATE]);
  3045.  
  3046.        // clip the objects polygons against viewing volume
  3047.  
  3048.        Clip_Object_3D(&static_obj[BARRIERS_TEMPLATE],CLIP_Z_MODE);
  3049.  
  3050.        // generate the final polygon list
  3051.  
  3052.        Generate_Poly_List(&static_obj[BARRIERS_TEMPLATE],ADD_TO_POLY_LIST);
  3053.        }
  3054.  
  3055.     }  // end for index
  3056.  
  3057.  
  3058.  
  3059. // phase 4: the main power station
  3060.  
  3061. for (index=0; index<NUM_STATIONS; index++)
  3062.     {
  3063.     // test if object is visible
  3064.  
  3065.     // now before we continue to process object, we must
  3066.     // move it to the proper world position
  3067.  
  3068.     static_obj[STATIONS_TEMPLATE].world_pos.x = stations[index].x;
  3069.     static_obj[STATIONS_TEMPLATE].world_pos.y = stations[index].y;
  3070.     static_obj[STATIONS_TEMPLATE].world_pos.z = stations[index].z;
  3071.  
  3072.     if (!Remove_Object(&static_obj[STATIONS_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  3073.        {
  3074.        // convert object local coordinates to world coordinate
  3075.  
  3076.        Local_To_World_Object(&static_obj[STATIONS_TEMPLATE]);
  3077.  
  3078.        // remove the backfaces and shade object
  3079.  
  3080.        Remove_Backfaces_And_Shade(&static_obj[STATIONS_TEMPLATE],-1);
  3081.  
  3082.        // convert world coordinates to camera coordinate
  3083.  
  3084.        World_To_Camera_Object(&static_obj[STATIONS_TEMPLATE]);
  3085.  
  3086.        // clip the objects polygons against viewing volume
  3087.  
  3088.        Clip_Object_3D(&static_obj[STATIONS_TEMPLATE],CLIP_Z_MODE);
  3089.  
  3090.        // generate the final polygon list
  3091.  
  3092.        Generate_Poly_List(&static_obj[STATIONS_TEMPLATE],ADD_TO_POLY_LIST);
  3093.        }
  3094.  
  3095.     }  // end for index
  3096.  
  3097. // phase 5: the telepods
  3098.  
  3099. for (index=0; index<NUM_TELEPODS; index++)
  3100.     {
  3101.     // test if object is visible
  3102.  
  3103.     // now before we continue to process object, we must
  3104.     // move it to the proper world position
  3105.  
  3106.     static_obj[TELEPODS_TEMPLATE].world_pos.x = telepods[index].x;
  3107.     static_obj[TELEPODS_TEMPLATE].world_pos.y = telepods[index].y;
  3108.     static_obj[TELEPODS_TEMPLATE].world_pos.z = telepods[index].z;
  3109.  
  3110.     if (!Remove_Object(&static_obj[TELEPODS_TEMPLATE],OBJECT_CULL_XYZ_MODE))
  3111.        {
  3112.        // convert object local coordinates to world coordinate
  3113.  
  3114.        Local_To_World_Object(&static_obj[TELEPODS_TEMPLATE]);
  3115.  
  3116.        // remove the backfaces and shade object
  3117.  
  3118.        Remove_Backfaces_And_Shade(&static_obj[TELEPODS_TEMPLATE],-1);
  3119.  
  3120.        // convert world coordinates to camera coordinate
  3121.  
  3122.        World_To_Camera_Object(&static_obj[TELEPODS_TEMPLATE]);
  3123.  
  3124.        // clip the objects polygons against viewing volume
  3125.  
  3126.        Clip_Object_3D(&static_obj[TELEPODS_TEMPLATE],CLIP_Z_MODE);
  3127.  
  3128.        // generate the final polygon list
  3129.  
  3130.        Generate_Poly_List(&static_obj[TELEPODS_TEMPLATE],ADD_TO_POLY_LIST);
  3131.        }
  3132.  
  3133.     }  // end for index
  3134.  
  3135. } // end Draw_Stationary_Objects
  3136.  
  3137. ///////////////////////////////////////////////////////////////////////////////
  3138.  
  3139. void Set_3D_View(void)
  3140. {
  3141. // this function sets up the 3d viewing system for the game
  3142.  
  3143. // set 2-D clipping region to take into consideration the instrument panels
  3144.  
  3145. poly_clip_min_y  = 0;
  3146. poly_clip_max_y  = 128;
  3147.  
  3148. // set up viewing and 3D clipping parameters
  3149.  
  3150. clip_near_z      = 125,
  3151. clip_far_z       = 6000,
  3152. viewing_distance = 250;
  3153.  
  3154. // turn the damn light up a bit!
  3155.  
  3156. ambient_light    = 8;
  3157.  
  3158. light_source.x   = 0.918926;
  3159. light_source.y   = 0.248436;
  3160. light_source.z   = -0.306359;
  3161.  
  3162. view_point.x = 0;
  3163. view_point.y = 40;
  3164. view_point.z = 0;
  3165.  
  3166. } // end Set_3D_View
  3167.  
  3168. ////////////////////////////////////////////////////////////////////////////////
  3169.  
  3170. void Load_3D_Objects(void)
  3171. {
  3172. // this function loads the 3-D models
  3173.  
  3174. int index; // looping variable
  3175.  
  3176. // load in dynamic game objects
  3177.  
  3178. // load in missile template
  3179.  
  3180. PLG_Load_Object(&dynamic_obj[MISSILES_TEMPLATE],"missile.plg",2);
  3181.  
  3182. // first fix template object at (0,0,0)
  3183.  
  3184. dynamic_obj[MISSILES_TEMPLATE].world_pos.x = 0;
  3185. dynamic_obj[MISSILES_TEMPLATE].world_pos.y = 0;
  3186. dynamic_obj[MISSILES_TEMPLATE].world_pos.z = 0;
  3187.  
  3188.  
  3189. // load in tallon alien template
  3190.  
  3191. PLG_Load_Object(&dynamic_obj[TALLONS_TEMPLATE],"tallon.plg",1);
  3192.  
  3193. // first fix template object at (0,0,0)
  3194.  
  3195. dynamic_obj[TALLONS_TEMPLATE].world_pos.x = 0;
  3196. dynamic_obj[TALLONS_TEMPLATE].world_pos.y = 0;
  3197. dynamic_obj[TALLONS_TEMPLATE].world_pos.z = 0;
  3198.  
  3199. // the "state" field is going to track the current angle of the object
  3200.  
  3201. dynamic_obj[TALLONS_TEMPLATE].state = 0; // pointing directly down the positive
  3202.                                          // Z-axis, this is the neutral position
  3203.  
  3204. // load in slider alien template
  3205.  
  3206. PLG_Load_Object(&dynamic_obj[SLIDERS_TEMPLATE],"slider.plg",1);
  3207.  
  3208. // first fix template object at (0,0,0)
  3209.  
  3210. dynamic_obj[SLIDERS_TEMPLATE].world_pos.x = 0;
  3211. dynamic_obj[SLIDERS_TEMPLATE].world_pos.y = 0;
  3212. dynamic_obj[SLIDERS_TEMPLATE].world_pos.z = 0;
  3213.  
  3214. // the "state" field is going to track the current angle of the object
  3215.  
  3216. dynamic_obj[SLIDERS_TEMPLATE].state = 0; // pointing directly down the positive
  3217.                                          // Z-axis, this is the neutral position
  3218.  
  3219.  
  3220. // load in static game objects, background, obstacles, etc.
  3221.  
  3222. // load in obstacle one template
  3223.  
  3224. PLG_Load_Object(&static_obj[OBSTACLES_1_TEMPLATE],"pylons.plg",1);
  3225.  
  3226. // first fix template object at (0,0,0)
  3227.  
  3228. static_obj[OBSTACLES_1_TEMPLATE].world_pos.x = 0;
  3229. static_obj[OBSTACLES_1_TEMPLATE].world_pos.y = 0;
  3230. static_obj[OBSTACLES_1_TEMPLATE].world_pos.z = 0;
  3231.  
  3232. // now position all obstacle copies
  3233.  
  3234. for (index=0; index<NUM_OBSTACLES_1; index++)
  3235.     {
  3236.  
  3237.     obstacles_1[index].state = 1;
  3238.     obstacles_1[index].rx    = 0;
  3239.     obstacles_1[index].ry    = 0;
  3240.     obstacles_1[index].rz    = 0;
  3241.     obstacles_1[index].x     = -8000 + rand()%16000;
  3242.     obstacles_1[index].y     = 0;
  3243.     obstacles_1[index].z     = -8000 + rand()%16000;
  3244.  
  3245.     } // end for index
  3246.  
  3247.  
  3248. // load in obstacle two template
  3249.  
  3250. PLG_Load_Object(&static_obj[OBSTACLES_2_TEMPLATE],"rock.plg",1);
  3251.  
  3252. // first fix template object at (0,0,0)
  3253.  
  3254. static_obj[OBSTACLES_2_TEMPLATE].world_pos.x = 0;
  3255. static_obj[OBSTACLES_2_TEMPLATE].world_pos.y = 0;
  3256. static_obj[OBSTACLES_2_TEMPLATE].world_pos.z = 0;
  3257.  
  3258. // now position all obstacle copies
  3259.  
  3260. for (index=0; index<NUM_OBSTACLES_2; index++)
  3261.     {
  3262.  
  3263.     obstacles_2[index].state = 1;
  3264.     obstacles_2[index].rx    = 0;
  3265.     obstacles_2[index].ry    = 0;
  3266.     obstacles_2[index].rz    = 0;
  3267.     obstacles_2[index].x     = -8000 + rand()%16000;
  3268.     obstacles_2[index].y     = 0;
  3269.     obstacles_2[index].z     = -8000 + rand()%16000;
  3270.  
  3271.     } // end for index
  3272.  
  3273. // load in tower template
  3274.  
  3275. PLG_Load_Object(&static_obj[TOWERS_TEMPLATE],"tower.plg",2);
  3276.  
  3277. // first fix template object at (0,0,0)
  3278.  
  3279. static_obj[TOWERS_TEMPLATE].world_pos.x = 0;
  3280. static_obj[TOWERS_TEMPLATE].world_pos.y = 0;
  3281. static_obj[TOWERS_TEMPLATE].world_pos.z = 0;
  3282.  
  3283. // now position all tower copies
  3284.  
  3285. for (index=0; index<NUM_TOWERS; index++)
  3286.     {
  3287.  
  3288.     towers[index].state = 1;
  3289.     towers[index].rx    = 0;
  3290.     towers[index].ry    = 0;
  3291.     towers[index].rz    = 0;
  3292.     towers[index].x     = 0;
  3293.     towers[index].y     = 0;
  3294.     towers[index].z     = 0;
  3295.  
  3296.     } // end for index
  3297.  
  3298. // position the towers
  3299.  
  3300. towers[0].x = -1500;
  3301. towers[0].z = 1500;
  3302.  
  3303. towers[1].x = -1500;
  3304. towers[1].z = -1500;
  3305.  
  3306. towers[2].x = 1500;
  3307. towers[2].z = -1500;
  3308.  
  3309. towers[3].x = 1500;
  3310. towers[3].z = 1500;
  3311.  
  3312.  
  3313.  
  3314. // load in telepod template
  3315.  
  3316. PLG_Load_Object(&static_obj[TELEPODS_TEMPLATE],"tele.plg",2);
  3317.  
  3318. // first fix template object at (0,0,0)
  3319.  
  3320. static_obj[TELEPODS_TEMPLATE].world_pos.x = 0;
  3321. static_obj[TELEPODS_TEMPLATE].world_pos.y = 0;
  3322. static_obj[TELEPODS_TEMPLATE].world_pos.z = 0;
  3323.  
  3324. // now position all tower copies
  3325.  
  3326. for (index=0; index<NUM_TELEPODS; index++)
  3327.     {
  3328.  
  3329.     telepods[index].state = 1;
  3330.     telepods[index].rx    = 0;
  3331.     telepods[index].ry    = 0;
  3332.     telepods[index].rz    = 0;
  3333.     telepods[index].x     = 0;
  3334.     telepods[index].y     = 0;
  3335.     telepods[index].z     = 0;
  3336.  
  3337.     } // end for index
  3338.  
  3339. // position the telepods
  3340.  
  3341. telepods[0].x = -6000;
  3342. telepods[0].z = 6000;
  3343.  
  3344. telepods[1].x = -6000;
  3345. telepods[1].z = -6000;
  3346.  
  3347. telepods[2].x = 6000;
  3348. telepods[2].z = -6000;
  3349.  
  3350. telepods[3].x = 6000;
  3351. telepods[3].z = 6000;
  3352.  
  3353.  
  3354. // load in universe boundary template
  3355.  
  3356. PLG_Load_Object(&static_obj[BARRIERS_TEMPLATE],"barrier.plg",2);
  3357.  
  3358. // first fix template object at (0,0,0)
  3359.  
  3360. static_obj[BARRIERS_TEMPLATE].world_pos.x = 0;
  3361. static_obj[BARRIERS_TEMPLATE].world_pos.y = 0;
  3362. static_obj[BARRIERS_TEMPLATE].world_pos.z = 0;
  3363.  
  3364. // now position all barrier copies
  3365.  
  3366. for (index=0; index<NUM_BARRIERS; index++)
  3367.     {
  3368.  
  3369.     barriers[index].state = 1;
  3370.     barriers[index].rx    = 0;
  3371.     barriers[index].ry    = 15;
  3372.     barriers[index].rz    = 0;
  3373.     barriers[index].x     = 0;
  3374.     barriers[index].y     = 0;
  3375.     barriers[index].z     = 0;
  3376.  
  3377.     } // end for index
  3378.  
  3379. // position the barriers
  3380.  
  3381. barriers[0].x = -8000;
  3382. barriers[0].z = 8000;
  3383.  
  3384. barriers[1].x = -8000;
  3385. barriers[1].z = 0;
  3386.  
  3387. barriers[2].x = -8000;
  3388. barriers[2].z = -8000;
  3389.  
  3390. barriers[3].x = 0;
  3391. barriers[3].z = -8000;
  3392.  
  3393. barriers[4].x = 8000;
  3394. barriers[4].z = -8000;
  3395.  
  3396. barriers[5].x = 8000;
  3397. barriers[5].z = 0;
  3398.  
  3399. barriers[6].x = 8000;
  3400. barriers[6].z = 8000;
  3401.  
  3402. barriers[7].x = 0;
  3403. barriers[7].z = 8000;
  3404.  
  3405. // load in power station template
  3406.  
  3407. PLG_Load_Object(&static_obj[STATIONS_TEMPLATE],"station.plg",2);
  3408.  
  3409. // first fix template object at (0,0,0)
  3410.  
  3411. static_obj[STATIONS_TEMPLATE].world_pos.x = 0;
  3412. static_obj[STATIONS_TEMPLATE].world_pos.y = 0;
  3413. static_obj[STATIONS_TEMPLATE].world_pos.z = 0;
  3414.  
  3415. // now position all power stations
  3416.  
  3417. for (index=0; index<NUM_STATIONS; index++)
  3418.     {
  3419.  
  3420.     stations[index].state = 1;
  3421.     stations[index].rx    = 0;
  3422.     stations[index].ry    = 0;
  3423.     stations[index].rz    = 0;
  3424.     stations[index].x     = 0;
  3425.     stations[index].y     = 0;
  3426.     stations[index].z     = 0;
  3427.  
  3428.     } // end for index
  3429.  
  3430. } // end Load_3D_Models
  3431.  
  3432.  
  3433.  
  3434.