home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_06 / robo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-23  |  20.3 KB  |  746 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.  
  19. #define CELL_COLUMNS   10  // size of cell based matrix
  20. #define CELL_ROWS      6
  21.  
  22. #define CELL_WIDTH     32  // width of a cell in pixels
  23. #define CELL_HEIGHT    32  // height of a cell in pixels
  24.  
  25. #define NUM_SCREENS    6   // number of screens in game
  26.  
  27. #define ROBO_MOVE      8   // speed that the player moves at
  28.  
  29. // G L O B A L S  ////////////////////////////////////////////////////////////
  30.  
  31. pcx_picture imagery_pcx,   // used to load in the imagery for robopunk
  32.             intro_pcx;     // the intro screen
  33.  
  34. sprite back_cells,  // background cells sprite
  35.        robopunk;    // robopunk
  36.  
  37. unsigned char far *double_buffer = NULL;
  38.  
  39. unsigned int buffer_height        = SCREEN_HEIGHT;
  40.  
  41. unsigned int buffer_size = SCREEN_WIDTH*SCREEN_HEIGHT/2;
  42.  
  43. // use an array of 2-D matrices to hold the screens
  44.  
  45. char **universe[NUM_SCREENS] = {NULL,NULL,NULL,NULL,NULL,NULL};
  46.  
  47. // here is screen 1, note: it's 10x6 cells where each cell is represented
  48. // by an ASCII character (makes it easier to draw each screen by hand).
  49. // later the ASCII characters will be translated to bitmap id's so that
  50. // the screen image can be drawn
  51.  
  52. char *screen_1[CELL_ROWS] = {"           ",
  53.                              "##*###*####",
  54.                              "###########",
  55.                              "<==========",
  56.                              "######:####",
  57.                              "####<=;=>##"};
  58.  
  59.  
  60. char *screen_2[CELL_ROWS] = {"      ###  ",
  61.                              "      #:#  ",
  62.                              "#######:###",
  63.                              "=======;===",
  64.                              "#<==>######",
  65.                              "###########"};
  66.  
  67.  
  68. char *screen_3[CELL_ROWS] = {"      ##<=>",
  69.                              "  #*##<==>#",
  70.                              "####*######",
  71.                              "===========",
  72.                              "###########",
  73.                              "###########"};
  74.  
  75.  
  76.  
  77. char *screen_4[CELL_ROWS] = {"###        ",
  78.                              "#<=>##     ",
  79.                              "####<==>###",
  80.                              "===========",
  81.                              "###########",
  82.                              "#<==>######"};
  83.  
  84.  
  85.  
  86. char *screen_5[CELL_ROWS] = {"   #<=>#   ",
  87.                              " #:#***#:##",
  88.                              "##:#####:##",
  89.                              "==;=====;==",
  90.                              "###########",
  91.                              "###########"};
  92.  
  93.  
  94. char *screen_6[CELL_ROWS] = {"           ",
  95.                              "##         ",
  96.                              "#*#*##     ",
  97.                              "========>  ",
  98.                              "#########  ",
  99.                              "#########  "};
  100.  
  101. // F U N C T I O N S /////////////////////////////////////////////////////////
  102.  
  103. void Show_Double_Buffer(unsigned char far *buffer)
  104. {
  105. // this functions copies the double buffer into the video buffer
  106.  
  107. _asm
  108.    {
  109.    push ds               ; save DS on stack
  110.    mov cx,buffer_size    ; this is the size of buffer in WORDS
  111.    les di,video_buffer   ; es:di is destination of memory move
  112.    lds si,buffer         ; ds:si is source of memory move
  113.    cld                   ; make sure to move in the right direction
  114.    rep movsw             ; move all the words
  115.    pop ds                ; restore the data segment
  116.    } // end asm
  117.  
  118. } // end Show_Double_Buffer
  119.  
  120. //////////////////////////////////////////////////////////////////////////////
  121.  
  122. int Create_Double_Buffer(int num_lines)
  123. {
  124.  
  125. // allocate enough memory to hold the double buffer
  126.  
  127. if ((double_buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * (num_lines + 1)))==NULL)
  128.    return(0);
  129.  
  130. // set the height of the buffer and compute it's size
  131.  
  132. buffer_height = num_lines;
  133.  
  134. buffer_size = SCREEN_WIDTH * num_lines/2;
  135.  
  136. // fill the buffer with black
  137.  
  138. _fmemset(double_buffer, 0, SCREEN_WIDTH * num_lines);
  139.  
  140. // everything was ok
  141.  
  142. return(1);
  143.  
  144. } // end Init_Double_Buffer
  145.  
  146. ///////////////////////////////////////////////////////////////////////////////
  147.  
  148. void Fill_Double_Buffer(int color)
  149. {
  150. // this function fills in the double buffer with the sent color
  151.  
  152. _fmemset(double_buffer, color, SCREEN_WIDTH * buffer_height);
  153.  
  154. } // end Fill_Double_Buffer
  155.  
  156. //////////////////////////////////////////////////////////////////////////////
  157.  
  158. void Delete_Double_Buffer(void)
  159. {
  160. // this function free's up the memory allocated by the double buffer
  161. // make sure to use FAR version
  162.  
  163. if (double_buffer)
  164.   _ffree(double_buffer);
  165.  
  166. } // end Delete_Double_Buffer
  167.  
  168. //////////////////////////////////////////////////////////////////////////////
  169.  
  170. void Plot_Pixel_Fast_DB(int x,int y,unsigned char color)
  171. {
  172.  
  173. // plots the pixel in the desired color a little quicker using binary shifting
  174. // to accomplish the multiplications
  175.  
  176. // use the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  177.  
  178. double_buffer[((y<<8) + (y<<6)) + x] = color;
  179.  
  180. } // end Plot_Pixel_Fast_DB
  181.  
  182. //////////////////////////////////////////////////////////////////////////////
  183.  
  184. void Behind_Sprite_DB(sprite_ptr sprite)
  185. {
  186.  
  187. // this function scans the background behind a sprite so that when the sprite
  188. // is draw, the background isnn'y obliterated
  189.  
  190. char far *work_back;
  191. int work_offset=0,offset,y;
  192.  
  193. // alias a pointer to sprite background for ease of access
  194.  
  195. work_back = sprite->background;
  196.  
  197. // compute offset of background in video buffer
  198.  
  199. offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  200.  
  201. for (y=0; y<sprite_height; y++)
  202.     {
  203.     // copy the next row out off screen buffer into sprite background buffer
  204.  
  205.     _fmemcpy((char far *)&work_back[work_offset],
  206.              (char far *)&double_buffer[offset],
  207.              sprite_width);
  208.  
  209.     // move to next line in double buffer and in sprite background buffer
  210.  
  211.     offset      += SCREEN_WIDTH;
  212.     work_offset += sprite_width;
  213.  
  214.     } // end for y
  215.  
  216. } // end Behind_Sprite_DB
  217.  
  218. //////////////////////////////////////////////////////////////////////////////
  219.  
  220. void Erase_Sprite_DB(sprite_ptr sprite)
  221. {
  222. // replace the background that was behind the sprite
  223.  
  224. // this function replaces the background that was saved from where a sprite
  225. // was going to be placed
  226.  
  227. char far *work_back;
  228. int work_offset=0,offset,y;
  229.  
  230. // alias a pointer to sprite background for ease of access
  231.  
  232. work_back = sprite->background;
  233.  
  234. // compute offset of background in double buffer
  235.  
  236. offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  237.  
  238. for (y=0; y<sprite_height; y++)
  239.     {
  240.     // copy the next row out off screen buffer into sprite background buffer
  241.  
  242.     _fmemcpy((char far *)&double_buffer[offset],
  243.              (char far *)&work_back[work_offset],
  244.              sprite_width);
  245.  
  246.     // move to next line in video buffer and in sprite background buffer
  247.  
  248.     offset      += SCREEN_WIDTH;
  249.     work_offset += sprite_width;
  250.  
  251.     } // end for y
  252.  
  253.  
  254. } // end Erase_Sprite_DB
  255.  
  256. //////////////////////////////////////////////////////////////////////////////
  257.  
  258. void Draw_Sprite_DB(sprite_ptr sprite)
  259. {
  260.  
  261. // this function draws a sprite on the screen row by row very quickly
  262. // note the use of shifting to implement multplication
  263.  
  264. char far *work_sprite;
  265. int work_offset=0,offset,x,y;
  266. unsigned char data;
  267.  
  268. // alias a pointer to sprite for ease of access
  269.  
  270. work_sprite = sprite->frames[sprite->curr_frame];
  271.  
  272. // compute offset of sprite in video buffer
  273.  
  274. offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  275.  
  276. for (y=0; y<sprite_height; y++)
  277.     {
  278.     // copy the next row into the double buffer using memcpy for speed
  279.  
  280.     for (x=0; x<sprite_width; x++)
  281.         {
  282.  
  283.         // test for transparent pixel i.e. 0, if not transparent then draw
  284.  
  285.         if ((data=work_sprite[work_offset+x]))
  286.              double_buffer[offset+x] = data;
  287.  
  288.         } // end for x
  289.  
  290.     // move to next line in double buffer and in sprite bitmap buffer
  291.  
  292.     offset      += SCREEN_WIDTH;
  293.     work_offset += sprite_width;
  294.  
  295.     } // end for y
  296.  
  297. } // end Draw_Sprite_DB
  298.  
  299. ///////////////////////////////////////////////////////////////////////////////
  300.  
  301. void Draw_Screen(char **screen)
  302. {
  303. // this function draws a screen by using the data in the universe array
  304. // each element in the universe array is a 2-D matrix of cells, these
  305. // cells are ASCII characters that represent the requested bitmap that
  306. // shoulf be placed in the cell location
  307.  
  308. char *curr_row;
  309.  
  310. int index_x, index_y, cell_number;
  311.  
  312. // translation table for screen database used to convert the ASCII
  313. // characters into id numbers
  314.  
  315. static char back_cell_lookup[] =
  316.  
  317.    { 0,0, 0, 4,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,1,2,3,0,
  318. // SP  !  " #  $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
  319.  
  320.     0,0,0,0,0,0,0,0,0,0, 0,0,0,0, 0,0,0,0,0,0,0,0 ,0,0,0,0,0,0 ,0, 0,0,0};
  321. //  @ A B C D E F G H I  J K L M  N O P Q R S T U  V W X Y Z [  \  ] ^ _
  322.  
  323. // clear out the double buffer
  324.  
  325. Fill_Double_Buffer(0);
  326.  
  327. // now draw the screen row by row
  328.  
  329. for (index_y = 0; index_y<CELL_ROWS; index_y++)
  330.     {
  331.  
  332.     // get the current row for speed
  333.  
  334.     curr_row = screen[index_y];
  335.  
  336.     // do the row
  337.  
  338.     for (index_x = 0; index_x<CELL_COLUMNS; index_x++)
  339.         {
  340.         // extract cell out of data structure and blit it onto screen
  341.  
  342.         cell_number = back_cell_lookup[curr_row[index_x]-32];
  343.  
  344.         // compute the screen x and y
  345.  
  346.         back_cells.x = index_x * sprite_width;
  347.         back_cells.y = index_y * sprite_height;
  348.  
  349.         // figure out which bitmap to draw
  350.  
  351.         back_cells.curr_frame = cell_number;
  352.  
  353.         // draw the bitmap
  354.  
  355.         Draw_Sprite_DB((sprite_ptr)&back_cells);
  356.  
  357.         } // end for index_x
  358.  
  359.     } // end for index_y
  360.  
  361. } // end Draw_Screen
  362.  
  363. //////////////////////////////////////////////////////////////////////////////
  364.  
  365. void Rotate_Lights(void)
  366. {
  367.  
  368. // this function useds color rotation to move the walkway lights
  369. // three color registers are used.
  370. // note: this function has static variables which track timing parameters
  371. // and also if the funtion has been entered yet.
  372.  
  373. static int clock=0,entered_yet=0;// used for timing, note: they are static!
  374.  
  375. RGB_color color,
  376.           color_1,
  377.           color_2,
  378.           color_3;
  379.  
  380. // this function blinks the running lights on the walkway
  381.  
  382. if (!entered_yet)
  383.    {
  384.  
  385.    // reset the palette registers 96,97,98 to red,
  386.    // black, black
  387.  
  388.    color.red   = 255;
  389.    color.green = 0;
  390.    color.blue  = 0;
  391.  
  392.    Set_Palette_Register(96,(RGB_color_ptr)&color);
  393.  
  394.    color.red = color.green = color.blue = 0;
  395.  
  396.    Set_Palette_Register(97,(RGB_color_ptr)&color);
  397.    Set_Palette_Register(98,(RGB_color_ptr)&color);
  398.  
  399.    // system has initialized, so flag it
  400.  
  401.    entered_yet=1;
  402.  
  403.    } // end if first time into function
  404.  
  405. // try and rotate the light colors i.e. color rotation
  406.  
  407.    if (++clock==3)  // is it time to rotate
  408.       {
  409.       // get the colors
  410.  
  411.       Get_Palette_Register(96,(RGB_color_ptr)&color_1);
  412.       Get_Palette_Register(97,(RGB_color_ptr)&color_2);
  413.       Get_Palette_Register(98,(RGB_color_ptr)&color_3);
  414.  
  415.       // set the colors
  416.  
  417.       Set_Palette_Register(97,(RGB_color_ptr)&color_1);
  418.       Set_Palette_Register(98,(RGB_color_ptr)&color_2);
  419.       Set_Palette_Register(96,(RGB_color_ptr)&color_3);
  420.  
  421.       // reset the clock
  422.  
  423.       clock=0;
  424.  
  425.       } // end if time to rotate
  426.  
  427. } // end Rotate_Lights
  428.  
  429. ///////////////////////////////////////////////////////////////////////////////
  430.  
  431. void Disolve(void)
  432. {
  433. // disolve screen by ploting zillions of black pixels
  434.  
  435. unsigned long index;
  436.  
  437. for (index=0; index<=300000; index++,Plot_Pixel_Fast(rand()%320, rand()%200, 0));
  438.  
  439. } // end Disolve
  440.  
  441. // M A I N ////////////////////////////////////////////////////////////////////
  442.  
  443. void main(void)
  444. {
  445.  
  446. int index,
  447.     curr_screen=0,
  448.     done=0;
  449.  
  450. // S E C T I O N   1  /////////////////////////////////////////////////////////
  451.  
  452. // set video mode to 320x200 256 color mode
  453.  
  454. Set_Video_Mode(VGA256);
  455.  
  456. // create a double buffer
  457.  
  458. if (!Create_Double_Buffer(SCREEN_HEIGHT))
  459.    {
  460.    printf("\nNot enough memory to create double buffer.");
  461.  
  462.    } // end if
  463.  
  464. // S E C T I O N   2  /////////////////////////////////////////////////////////
  465.  
  466. // load intro screen and display for a few secs.
  467.  
  468. PCX_Init((pcx_picture_ptr)&intro_pcx);
  469.  
  470. PCX_Load("roboint.pcx", (pcx_picture_ptr)&intro_pcx,1);
  471.  
  472. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  473.  
  474. // let user see it
  475.  
  476. Delay(50);
  477.  
  478. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  479.  
  480. // S E C T I O N   3  /////////////////////////////////////////////////////////
  481.  
  482. // load in background and animation cells
  483.  
  484. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  485.  
  486. PCX_Load("robopunk.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  487.  
  488. // initialize sprite size
  489.  
  490. sprite_width  = 32;
  491. sprite_height = 32;
  492.  
  493. // create a sprite for robopunk
  494.  
  495. Sprite_Init((sprite_ptr)&robopunk,0,0,0,0,0,0);
  496.  
  497. // create a sprite to hold the background cells
  498.  
  499. Sprite_Init((sprite_ptr)&back_cells,0,0,0,0,0,0);
  500.  
  501. // extract animation cells for robopunk
  502.  
  503. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,0,3,0);
  504. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,1,5,0);
  505. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,2,4,0);
  506. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,3,5,0);
  507. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,4,6,0);
  508. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,5,1,0);
  509. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,6,2,0);
  510. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,7,1,0);
  511. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&robopunk,8,0,0);
  512.  
  513.  
  514. // extract background cells
  515.  
  516. for (index=0; index<8; index++)
  517.     {
  518.  
  519.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,(sprite_ptr)&back_cells,index,index,1);
  520.  
  521.     } // end for index
  522.  
  523. // done with pcx file so obliterate it
  524.  
  525. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  526.  
  527. // S E C T I O N   4  /////////////////////////////////////////////////////////
  528.  
  529. // set up universe data structure
  530.  
  531. universe[0] = (char **)screen_1;
  532. universe[1] = (char **)screen_2;
  533. universe[2] = (char **)screen_3;
  534. universe[3] = (char **)screen_4;
  535. universe[4] = (char **)screen_5;
  536. universe[5] = (char **)screen_6;
  537.  
  538. Draw_Screen((char **)universe[curr_screen]);
  539. Show_Double_Buffer(double_buffer);
  540.  
  541. // place robopunk
  542.  
  543. robopunk.x = 160;
  544. robopunk.y = 74;
  545.  
  546. robopunk.curr_frame = 0;
  547.  
  548. // scan background under robopunk
  549.  
  550. Behind_Sprite_DB((sprite_ptr)&robopunk);
  551.  
  552. // S E C T I O N   5  /////////////////////////////////////////////////////////
  553.  
  554. // main event loop
  555.  
  556. while(!done)
  557.      {
  558.  
  559. // S E C T I O N   6  /////////////////////////////////////////////////////////
  560.  
  561.      // erase robopunk
  562.  
  563.      Erase_Sprite_DB((sprite_ptr)&robopunk);
  564.  
  565.      // test if user has hit key
  566.  
  567.      if (kbhit())
  568.         {
  569.         // get the key
  570.  
  571. // S E C T I O N   7  /////////////////////////////////////////////////////////
  572.  
  573.         switch(getch())
  574.               {
  575.  
  576.               case 'a': // move the player left
  577.                       {
  578.                       // advance the animation frame and move player
  579.  
  580.                       // test if player is moving right, if so
  581.                       // show player turning before moving
  582.  
  583.                       if (robopunk.curr_frame > 0 && robopunk.curr_frame < 5)
  584.                          {
  585.                          robopunk.curr_frame = 0;
  586.                          } // end if player going right
  587.                       else
  588.                       if (robopunk.curr_frame == 0 )
  589.                          robopunk.curr_frame = 5;
  590.                       else
  591.                          {
  592.                          // player is already in leftward motion so continue
  593.  
  594.                          if (++robopunk.curr_frame > 8)
  595.                             robopunk.curr_frame = 5;
  596.  
  597.                          // move player to left
  598.  
  599.                          robopunk.x-=ROBO_MOVE;
  600.  
  601.                          // test if edge was hit
  602.  
  603.                          if (robopunk.x < 8)
  604.                             {
  605.                             // test if there is another screen to the left
  606.  
  607.                             if (curr_screen==0)
  608.                                {
  609.                                robopunk.x += ROBO_MOVE;
  610.                                } // end if already at end of universe
  611.                             else
  612.                                {
  613.                                // warp robopunk to other edge of screen
  614.                                // and change screens
  615.  
  616.                                robopunk.x = SCREEN_WIDTH - 40;
  617.  
  618.                                // scroll to next screen to the left
  619.  
  620.                                curr_screen--;
  621.  
  622.                                Draw_Screen((char **)universe[curr_screen]);
  623.  
  624.                                } // end else move a screen to the left
  625.  
  626.                             } // end if hit left edge of screen
  627.  
  628.                          } // end else
  629.  
  630.                       } break;
  631.  
  632.  
  633.               case 's': // move the player right
  634.                       {
  635.  
  636.                       // advance the animation frame and move player
  637.  
  638.                       // test if player is moving left, if so
  639.                       // show player turning before moving
  640.  
  641.                       if (robopunk.curr_frame > 4)
  642.                          {
  643.                          robopunk.curr_frame = 0;
  644.                          } // end if player going right
  645.                       else
  646.                       if (robopunk.curr_frame == 0 )
  647.                          robopunk.curr_frame =1;
  648.                       else
  649.                          {
  650.                          // player is already in rightward motion so continue
  651.  
  652.                          if (++robopunk.curr_frame > 4)
  653.                             robopunk.curr_frame = 1;
  654.  
  655.                          // move player to right
  656.  
  657.                          robopunk.x+=ROBO_MOVE;
  658.  
  659.                          // test if edge was hit
  660.  
  661.                          if (robopunk.x > SCREEN_WIDTH-40)
  662.                             {
  663.                             // test if there is another screen to the left
  664.  
  665.                             if (curr_screen==5)
  666.                                {
  667.                                robopunk.x -= ROBO_MOVE;
  668.                                } // end if already at end of universe
  669.                             else
  670.                                {
  671.                                // warp robopunk to other edge of screen
  672.                                // and change screens
  673.  
  674.                                robopunk.x = 8;
  675.  
  676.                                // scroll to next screen to the right
  677.  
  678.                                curr_screen++;
  679.  
  680.                                Draw_Screen((char **)universe[curr_screen]);
  681.  
  682.                                } // end else move a screen to the right
  683.  
  684.                             } // end if hit right edge of screen
  685.  
  686.                          } // end else
  687.  
  688.                       } break;
  689.  
  690.               case 'q': // exit the demo
  691.                       {
  692.                       done=1;
  693.  
  694.                       } break;
  695.  
  696.               default:break;
  697.  
  698.               } // end switch
  699.  
  700.         } // end if keyboard hit
  701.  
  702. // S E C T I O N   8  /////////////////////////////////////////////////////////
  703.  
  704.      // scan background under robopunk
  705.  
  706.      Behind_Sprite_DB((sprite_ptr)&robopunk);
  707.  
  708.      // draw him
  709.  
  710.      Draw_Sprite_DB((sprite_ptr)&robopunk);
  711.  
  712.      // do any background animation
  713.  
  714. // S E C T I O N   9  /////////////////////////////////////////////////////////
  715.  
  716.      // move the walkway lights
  717.  
  718.      Rotate_Lights();
  719.  
  720.      // show the double buffer
  721.  
  722.      Show_Double_Buffer(double_buffer);
  723.  
  724.      // wait a bit
  725.  
  726.      Delay(1);
  727.  
  728.      } // end while
  729.  
  730. // S E C T I O N   10 /////////////////////////////////////////////////////////
  731.  
  732. // use one of screen fx as exit
  733.  
  734. Disolve();
  735.  
  736. // reset the video mode back to text
  737.  
  738. Set_Video_Mode(TEXT_MODE);
  739.  
  740. // free the double buffer
  741.  
  742. Delete_Double_Buffer();
  743.  
  744. } // end main
  745.  
  746.