home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_11 / lunar.c < prev    next >
Text File  |  1994-07-05  |  15KB  |  624 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16. #include "graph3.h"  // include our graphics stuff
  17. #include "graph4.h"
  18. #include "graph5.h"
  19. #include "graph6.h"
  20.  
  21. // D E F I N E S /////////////////////////////////////////////////////////////
  22.  
  23. #define KEYBOARD_INT    0x09   // the keyboard interrupt number
  24. #define KEY_BUFFER      0x60   // the location of the keyboard buffer
  25. #define KEY_CONTROL     0x61   // the location of the keyboard controller
  26. #define INT_CONTROL     0x20   // the location of the interrupt controller
  27.  
  28. // make and break codes for the arrow keys (note the make codes are the
  29. // same as the scan codes and the break codes are just the scan codes plus
  30. // 128.  For example the scan code for the UP key is 72 which is the make
  31. // code.  if we add 128 to this then the result is 128+72 = 200.
  32.  
  33. // arrow keys
  34.  
  35. #define MAKE_RIGHT      77
  36. #define MAKE_LEFT       75
  37. #define MAKE_UP         72
  38. #define MAKE_DOWN       80
  39.  
  40. // some useful control keys
  41.  
  42. #define MAKE_ENTER      28
  43. #define MAKE_TAB        15
  44. #define MAKE_SPACE      57
  45. #define MAKE_CTRL       29
  46. #define MAKE_ALT        56
  47. #define MAKE_ESC        1
  48.  
  49. // and now the break codes
  50.  
  51. #define BREAK_RIGHT     205
  52. #define BREAK_LEFT      203
  53. #define BREAK_UP        200
  54. #define BREAK_DOWN      208
  55.  
  56. #define BREAK_ENTER     156
  57. #define BREAK_TAB       143
  58. #define BREAK_SPACE     185
  59. #define BREAK_CTRL      157
  60. #define BREAK_ALT       184
  61. #define BREAK_ESC       129
  62.  
  63. // indices into arrow key state table
  64.  
  65. #define INDEX_UP        0
  66. #define INDEX_DOWN      1
  67. #define INDEX_RIGHT     2
  68. #define INDEX_LEFT      3
  69.  
  70. #define INDEX_ENTER     4
  71. #define INDEX_TAB       5
  72. #define INDEX_SPACE     6
  73. #define INDEX_CTRL      7
  74. #define INDEX_ALT       8
  75. #define INDEX_ESC       9
  76.  
  77. #define NUM_KEYS       10  // number of keys in look up table
  78.  
  79. // G L O B A L S /////////////////////////////////////////////////////////////
  80.  
  81. void (_interrupt _far *Old_Key_Isr)();  // holds old keyboard interrupt handler
  82.  
  83. int raw_key;  // the global raw keyboard data
  84.  
  85. // the arrow key state table
  86.  
  87. int key_table[NUM_KEYS] = {0,0,0,0,0,0,0,0,0,0};
  88.  
  89.  
  90. // globals for the demo
  91.  
  92. int land_sx = 160,    // starting x of the landing pad
  93.     land_ex = 180,    // ending x of the landing pad
  94.     land_y  = 170;    // the y position of the platform
  95.  
  96. float lander_xv = 0,    // the initial velocity of the lunar lander
  97.       lander_yv = 0,
  98.       fuel      = 1000; // initial load of fuel
  99.  
  100. int right_engine = 0,   // these track which engines need to be displayed
  101.     left_engine  = 0,
  102.     up_engine    = 0,
  103.     down_engine  = 0;
  104.  
  105. pcx_picture imagery_pcx,      // the game imagery
  106.             background_pcx;   // the backdrop
  107.  
  108. // the sprite used in the game
  109.  
  110. sprite lander;                // the lunar lander
  111.  
  112. // F U N C T I O N S ////////////////////////////////////////////////////////
  113.  
  114. void _interrupt _far New_Key_Int()
  115. {
  116.  
  117. // read the key from the hardware and then re-enable the keyboard to
  118. // read another key
  119.  
  120. _asm
  121.    {
  122.    sti                    ; re-enable interrupts
  123.    in al, KEY_BUFFER      ; get the key that was pressed
  124.    xor ah,ah              ; zero out upper 8 bits of AX
  125.    mov raw_key, ax        ; store the key in global variable
  126.    in al, KEY_CONTROL     ; set the control register
  127.    or al, 82h             ; set the proper bits to reset the keyboard flip flop
  128.    out KEY_CONTROL,al     ; send the new data back to the control register
  129.    and al,7fh
  130.    out KEY_CONTROL,al     ; complete the reset
  131.    mov al,20h
  132.    out INT_CONTROL,al     ; re-enable interrupts
  133.                           ; this is not really needed since we are using the
  134.                           ; C _interrupt function type, it does this for us,
  135.                           ; however, it's a good habit to get into and can't
  136.                           ; hurt
  137.  
  138.    } // end inline assembly
  139.  
  140. // now for some C to update the arrow state table
  141.  
  142. // process the key and update the key state table
  143.  
  144. switch(raw_key)
  145.       {
  146.       case MAKE_UP:    // pressing up
  147.            {
  148.            key_table[INDEX_UP]    = 1;
  149.            } break;
  150.  
  151.       case MAKE_DOWN:  // pressing down
  152.            {
  153.            key_table[INDEX_DOWN]  = 1;
  154.            } break;
  155.  
  156.       case MAKE_RIGHT: // pressing right
  157.            {
  158.            key_table[INDEX_RIGHT] = 1;
  159.            } break;
  160.  
  161.       case MAKE_LEFT:  // pressing left
  162.            {
  163.            key_table[INDEX_LEFT]  = 1;
  164.            } break;
  165.  
  166.       case MAKE_ENTER:    // pressing enter
  167.            {
  168.            key_table[INDEX_ENTER]    = 1;
  169.            } break;
  170.  
  171.       case MAKE_TAB :  // pressing tab
  172.            {
  173.            key_table[INDEX_TAB ]  = 1;
  174.            } break;
  175.  
  176.       case MAKE_SPACE : // pressing space
  177.            {
  178.            key_table[INDEX_SPACE ] = 1;
  179.            } break;
  180.  
  181.       case MAKE_CTRL :  // pressing control
  182.            {
  183.            key_table[INDEX_CTRL ]  = 1;
  184.            } break;
  185.  
  186.       case MAKE_ALT  : // pressing alt
  187.            {
  188.            key_table[INDEX_ALT  ] = 1;
  189.            } break;
  190.  
  191.       case MAKE_ESC  :  // pressing escape
  192.            {
  193.            key_table[INDEX_ESC ]  = 1;
  194.            } break;
  195.  
  196.       case BREAK_UP:    // releasing up
  197.            {
  198.            key_table[INDEX_UP]    = 0;
  199.            } break;
  200.  
  201.       case BREAK_DOWN:  // releasing down
  202.            {
  203.            key_table[INDEX_DOWN]  = 0;
  204.            } break;
  205.  
  206.       case BREAK_RIGHT: // releasing right
  207.            {
  208.            key_table[INDEX_RIGHT] = 0;
  209.            } break;
  210.  
  211.       case BREAK_LEFT:  // releasing left
  212.            {
  213.            key_table[INDEX_LEFT]  = 0;
  214.            } break;
  215.  
  216.       case BREAK_ENTER:    // releasing enter
  217.            {
  218.            key_table[INDEX_ENTER]   = 0;
  219.            } break;
  220.  
  221.       case BREAK_TAB :  // releasing tab
  222.            {
  223.            key_table[INDEX_TAB ]  = 0;
  224.            } break;
  225.  
  226.       case BREAK_SPACE : // releasing space
  227.            {
  228.            key_table[INDEX_SPACE ] = 0;
  229.            } break;
  230.  
  231.       case BREAK_CTRL :  // releasing control
  232.            {
  233.            key_table[INDEX_CTRL ]  = 0;
  234.            } break;
  235.  
  236.       case BREAK_ALT  : // releasing alt
  237.            {
  238.            key_table[INDEX_ALT  ] = 0;
  239.            } break;
  240.  
  241.       case BREAK_ESC  :  // releasing escape
  242.            {
  243.            key_table[INDEX_ESC ]  = 0;
  244.            } break;
  245.  
  246.       default: break;
  247.  
  248.       } // end switch
  249.  
  250. // note how we don't chain interrupts, we want total control of the keyboard
  251. // however, if you wanted to chain then you would make a call to the old
  252. // keyboard handler right here.
  253.  
  254.  
  255. } // end New_Key_Int
  256.  
  257. ///////////////////////////////////////////////////////////////////////////////
  258.  
  259. void Install_Keyboard(void)
  260. {
  261.  
  262. Old_Key_Isr = _dos_getvect(KEYBOARD_INT);
  263.  
  264. _dos_setvect(KEYBOARD_INT, New_Key_Int);
  265.  
  266. } // end Install_Keyboard
  267.  
  268. ///////////////////////////////////////////////////////////////////////////////
  269.  
  270. void Delete_Keyboard(void)
  271. {
  272.  
  273. _dos_setvect(KEYBOARD_INT, Old_Key_Isr);
  274.  
  275. } // end Delete_Keyboard
  276.  
  277. // M A I N ///////////////////////////////////////////////////////////////////
  278.  
  279. void main(void)
  280. {
  281. int done=0,     // system exit flag
  282.     index,      // looping variable
  283.     score;      // used to compute score
  284.  
  285. char string[80];  // used for printing
  286.  
  287. // SECTION 1 /////////////////////////////////////////////////////////////////
  288.  
  289. // install the keyboard driver
  290.  
  291. Install_Keyboard();
  292.  
  293. // set video mode to 320x200 256 color mode
  294.  
  295. Set_Video_Mode(VGA256);
  296.  
  297. // create a double buffer
  298.  
  299. if (!Create_Double_Buffer(SCREEN_HEIGHT))
  300.    {
  301.    printf("\nNot enough memory to create double buffer.");
  302.  
  303.    } // end if
  304.  
  305. // clear the double buffer
  306.  
  307. Fill_Double_Buffer(0);
  308.  
  309. // SECTION 2 /////////////////////////////////////////////////////////////////
  310.  
  311. // load in the background image into the double buffer
  312.  
  313. PCX_Init((pcx_picture_ptr)&background_pcx);
  314.  
  315. PCX_Load("moon.pcx", (pcx_picture_ptr)&background_pcx,1);
  316.  
  317. // copy the background into the double buffer
  318.  
  319. _fmemcpy((char far *)double_buffer,
  320.          (char far *)(background_pcx.buffer),
  321.          SCREEN_WIDTH*SCREEN_HEIGHT);
  322.  
  323. PCX_Delete((pcx_picture_ptr)&background_pcx);
  324.  
  325. // load in imagery for lunar lander
  326.  
  327. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  328.  
  329. PCX_Load("lander.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  330.  
  331. // initialize player and extract bitmaps
  332.  
  333. sprite_width  = 16;
  334. sprite_height = 16;
  335.  
  336. Sprite_Init((sprite_ptr)&lander,0,0,0,0,0,0);
  337.  
  338. for (index=0; index<5; index++)
  339.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  340.                     (sprite_ptr)&lander,index,index,0);
  341.  
  342. // set position of lander
  343.  
  344. lander.x          = 100;
  345. lander.y          = 10;
  346. lander.curr_frame = 0;
  347. lander.state      = 1;
  348.  
  349. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  350.  
  351. // scan background under lander
  352.  
  353. Behind_Sprite_DB((sprite_ptr)&lander);
  354.  
  355.  
  356. // SECTION 3 /////////////////////////////////////////////////////////////////
  357.  
  358. // main event loop
  359.  
  360. while(!done)
  361.      {
  362.  
  363.      // erase the lander
  364.  
  365.      Erase_Sprite_DB((sprite_ptr)&lander);
  366.  
  367.      // transform the lander, notice how we look at the keyboard state table
  368.  
  369.      // reset current frame of lander and active engines
  370.  
  371.      lander.curr_frame = 0;
  372.      right_engine = left_engine = down_engine = up_engine = 0;
  373.  
  374.      // now we will look into the keyboard table to see what keys are being
  375.      // pressed, note that this table is updated not by the main(), but by
  376.      // the keyboard interrupt, this allows us to track multiple keys
  377.      // simulataneously
  378.  
  379. // SECTION 4 /////////////////////////////////////////////////////////////////
  380.  
  381.      // test if user is exiting
  382.  
  383.      if (key_table[INDEX_ESC]) done=1;
  384.  
  385.      // test the motion keys
  386.  
  387.      if (key_table[INDEX_RIGHT])
  388.         {
  389.  
  390.         // increase x velocity
  391.  
  392.         lander_xv+=.1;
  393.  
  394.         // limit velocity
  395.  
  396.         if (lander_xv>3)
  397.             lander_xv=3;
  398.  
  399.         // set engine flag
  400.  
  401.         right_engine = 1;
  402.  
  403.         // expend fuel
  404.  
  405.         fuel-=.5;
  406.  
  407.         } // end if
  408.  
  409.      if (key_table[INDEX_LEFT])
  410.         {
  411.         // decrease x velocity
  412.  
  413.         lander_xv-=.1;
  414.  
  415.         // limit velocity
  416.  
  417.         if (lander_xv<-3)
  418.             lander_xv=-3;
  419.  
  420.         // set engine flag
  421.  
  422.         left_engine = 1;
  423.  
  424.         // expend fuel
  425.  
  426.         fuel-=.5;
  427.  
  428.         } // end if
  429.  
  430.      if (key_table[INDEX_UP])
  431.         {
  432.         // decrease y velocity
  433.  
  434.         lander_yv-=.1;
  435.  
  436.         // limit velocity
  437.  
  438.         if (lander_yv<-3)
  439.             lander_yv=-3;
  440.  
  441.         // set engine flag
  442.  
  443.         up_engine = 1;
  444.  
  445.         // expend fuel
  446.  
  447.         fuel-=.5;
  448.  
  449.         } // end if
  450.  
  451.      if (key_table[INDEX_DOWN])
  452.         {
  453.         // increase y velocity
  454.  
  455.         lander_yv+=.1;
  456.  
  457.         // limit velocity
  458.  
  459.         if (lander_yv>4)
  460.             lander_yv=4;
  461.  
  462.         // set engine flag
  463.  
  464.         down_engine = 1;
  465.  
  466.         // expend fuel
  467.  
  468.         fuel-=.5;
  469.  
  470.         } // end if
  471.  
  472. // SECTION 5 /////////////////////////////////////////////////////////////////
  473.  
  474.      // based on current velocity, move lander
  475.  
  476.      lander.x = lander.x + (int)(lander_xv+.5);
  477.      lander.y = lander.y + (int)(lander_yv+.5);
  478.  
  479.      // check if lander has moved off screen boundary
  480.  
  481.      // x tests
  482.  
  483.      if (lander.x > 320-16)
  484.          lander.x = 0;
  485.      else
  486.      if (lander.x < 0)
  487.          lander.x = 320-16;
  488.  
  489.      // y tests
  490.  
  491.      if (lander.y > 190-16)
  492.          lander.y = 190-16;
  493.      else
  494.      if (lander.y < 0)
  495.          lander.y = 0;
  496.  
  497. // SECTION 6 /////////////////////////////////////////////////////////////////
  498.  
  499.      // apply gravity
  500.  
  501.      lander_yv+=.05;
  502.  
  503.      if (lander_yv>3)
  504.         lander_yv=3;
  505.  
  506.      // expend fuel
  507.  
  508.      fuel-=.02;
  509.  
  510.      // draw the lander
  511.  
  512.      Behind_Sprite_DB((sprite_ptr)&lander);
  513.  
  514. // SECTION 7 /////////////////////////////////////////////////////////////////
  515.  
  516.      // based on the engines that are on, draw the lander
  517.  
  518.      // always draw the standard lander without engines first
  519.  
  520.      lander.curr_frame = 0;
  521.      Draw_Sprite_DB((sprite_ptr)&lander);
  522.  
  523.      // draw any engines that are on
  524.  
  525.      if (right_engine)
  526.         {
  527.         lander.curr_frame = 2;
  528.         Draw_Sprite_DB((sprite_ptr)&lander);
  529.         } // end if
  530.  
  531.      if (left_engine)
  532.         {
  533.         lander.curr_frame = 3;
  534.         Draw_Sprite_DB((sprite_ptr)&lander);
  535.         } // end if
  536.  
  537.      if (up_engine)
  538.         {
  539.         lander.curr_frame = 1;
  540.         Draw_Sprite_DB((sprite_ptr)&lander);
  541.         } // end if
  542.  
  543.      if (down_engine)
  544.         {
  545.         lander.curr_frame = 4;
  546.         Draw_Sprite_DB((sprite_ptr)&lander);
  547.         } // end if
  548.  
  549. // SECTION 8 /////////////////////////////////////////////////////////////////
  550.  
  551.      // draw indicators
  552.  
  553.      if (fuel<0) fuel=0;
  554.  
  555.      sprintf(string,"Fuel = %.2f  ",fuel);
  556.      Blit_String_DB(10,2,10,string,0);
  557.  
  558.      sprintf(string,"XV = %.2f  ",lander_xv);
  559.      Blit_String_DB(10,12,10,string,0);
  560.  
  561.      sprintf(string,"YV = %.2f  ",lander_yv);
  562.      Blit_String_DB(10,22,10,string,0);
  563.  
  564.      // show the double buffer
  565.  
  566.      Show_Double_Buffer(double_buffer);
  567.  
  568.      // wait a while
  569.  
  570.      Delay(1);
  571.  
  572. // SECTION 9 /////////////////////////////////////////////////////////////////
  573.  
  574.      // test if the lander has landed
  575.  
  576.      if (lander.x >= 245 && lander.x <= (266-16) && lander.y >= (185-16) &&
  577.          lander_yv < 2.0)
  578.          {
  579.          // print banner
  580.  
  581.          Blit_String(2,60,15,"T H E  E A G L E  H A S  L A N D E D!",1);
  582.  
  583.          // compute score based on fuel and velocity
  584.  
  585.          score = (int)(fuel*10 - lander_yv * 100);
  586.  
  587.          if (score < 0) score = 0;
  588.  
  589.          sprintf(string,"Score was %d",score);
  590.          Blit_String(100,110,15,string,1);
  591.  
  592.          // wait a second
  593.  
  594.          Delay(100);
  595.  
  596.          // fade everything
  597.  
  598.          Fade_Lights();
  599.  
  600.          // exit system
  601.  
  602.          done=1;
  603.  
  604.          } // end if the lander has landed
  605.  
  606.      } // end while
  607.  
  608. // SECTION 10 ////////////////////////////////////////////////////////////////
  609.  
  610. // delete the keyboard driver
  611.  
  612. Delete_Keyboard();
  613.  
  614. // reset the video mode back to text
  615.  
  616. Set_Video_Mode(TEXT_MODE);
  617.  
  618. // free the double buffer
  619.  
  620. Delete_Double_Buffer();
  621.  
  622. } // end main
  623.  
  624.