home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / GRAPHICS / MISC / STK100.ZIP / DEMOSRC.COM / SM.C next >
Encoding:
C/C++ Source or Header  |  1990-10-20  |  22.4 KB  |  713 lines

  1. /**********************************************************************
  2. * sm.c
  3. *
  4. * StarMines - a sprite toolkit demonstration game.
  5. *
  6. * Compile with the following command line:
  7. *
  8. * tcc -ms sm.c smspr.c stks.lib graphics.lib
  9. *
  10. **********************************************************************
  11.                     This file is part of
  12.  
  13.           STK -- The sprite toolkit -- version 1.0
  14.  
  15.               Copyright (C) Jari Karjala 1990
  16.  
  17. The sprite toolkit (STK) is a FreeWare toolkit for creating high
  18. resolution sprite graphics with PCompatible hardware. This toolkit 
  19. is provided as is without any warranty or such thing. See the file
  20. COPYING for further information.
  21.  
  22. **********************************************************************
  23. **********************************************************************/
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28.  
  29. #include <alloc.h>
  30. #include <dos.h>
  31. #include <graphics.h>
  32.  
  33. #include "stk.h"
  34.  
  35. #include "sm.h"
  36. #include "smspr.h"
  37.  
  38. int sprite_resolution = 8;
  39. ALIEN_TYPE aliens[MAX_ALIEN] = { NULL };
  40. ANIM_SPRITE player = NULL;
  41. ANIM_SPRITE player_explosion = NULL;
  42.  
  43. int player_dying;       /** non-zero when player is exploding **/
  44. int player_dead;        /** non-zero when player has exploded **/
  45. int player_immune;      /** non-zero when player is invincible **/
  46.  
  47. int lives;              /** number of lives **/
  48. long int score;         /** current score **/
  49. int score_inc;          /** score increment **/
  50. int bonus;              /** bonus after wave **/
  51.  
  52. int alien_count;        /** number of aliens alive **/
  53. int max_aliens;         /** initial number of aliens **/
  54. int alien_timeout;      /** timeout before divide **/
  55. int alien_speed;        /** alien speed **/
  56.  
  57. struct dir_struc {
  58.     int dx,dy;
  59. };
  60. struct dir_struc player_dirs[16] = { 
  61.     2,0,  2,-1, 2,-2, 1,-2, 0,-2, -1,-2, -2,-2, -2, -1, 
  62.    -2,0, -2,1, -2,2, -1,2,  0,2,   1,2,   2,2,   2,1
  63. };
  64.  
  65. #define MAX_DX 8
  66. #define MAX_DY 6
  67.  
  68. #define STARMINES   "StarMines"
  69. #define STARMINES_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 - (8*strlen(STARMINES))/2)
  70. #define STARMINES_Y (BOX_TOP+12)
  71.  
  72. #define COPYRIGHT   "Copyright (C) J.Karjala 1990"
  73. #define COPYRIGHT_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 - (8*strlen(COPYRIGHT))/2)
  74. #define COPYRIGHT_Y (BOX_BOT-16)
  75.  
  76. #define GAME_OVER   "*** GAME OVER ***"
  77. #define GAME_OVER_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 - (8*strlen(GAME_OVER))/2)
  78. #define GAME_OVER_Y (BOX_BOT-45)
  79. #define GAME_OVER2   "Press SPACE to start"
  80. #define GAME_OVER2_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 -(8*strlen(GAME_OVER2))/2)
  81. #define GAME_OVER2_Y (BOX_BOT-35)
  82.  
  83. #define NEXT_WAVE1      "+*+ BONUS %05d +*+"
  84. #define NEXT_WAVE2      "*+* BONUS %05d *+*"
  85. #define NEXT_WAVE_CLEAR "                    "
  86. #define NEXT_WAVE_X (BOX_LEF +(BOX_RIG-BOX_LEF)/2 -(8*strlen(NEXT_WAVE1)+1)/2)
  87. #define NEXT_WAVE_Y (BOX_BOT-40)
  88.  
  89. #define SCORE_X     (BOX_LEF+20)
  90. #define SCORE_Y     (BOX_TOP+40)
  91. #define LIVES_X     (BOX_RIG-20-8*8)
  92. #define LIVES_Y     (BOX_TOP+40)
  93.  
  94.  
  95. /**********************************************************************
  96. * Increment the score by i and display it
  97. **********************************************************************/
  98. void inc_score(int i)
  99. {
  100.     score += (long)i;
  101.     gr_dual_xy_printf(SCORE_X, SCORE_Y, "SCORE %06ld", score);
  102. }
  103. /**********************************************************************
  104. * Decrement lives
  105. **********************************************************************/
  106. void dec_lives(void)
  107. {
  108.     if (lives>0)
  109.         lives--;
  110.     
  111.     gr_dual_xy_printf(LIVES_X, LIVES_Y, "LIVES %d", lives);
  112. }
  113.  
  114.  
  115. /**********************************************************************
  116. * Set new limits for the given sprite at position x,y
  117. **********************************************************************/
  118. void set_limits(ANIM_SPRITE as, int x, int y)
  119. {
  120.     ANIM_SPR_INFO *asi;
  121.     int top, bot, lef, rig;
  122.     
  123.     asi = spr_anim_get_info(as);
  124.     
  125.     lef = 0; rig = gr_max_x;
  126.     top = 0; bot = gr_max_y;
  127.     
  128.     if (x>BOX_RIG) {
  129.         lef = BOX_RIG; rig = gr_max_x;
  130.     }
  131.     else if (x < (BOX_LEF - asi->w)) {
  132.         lef = 0; rig = BOX_LEF;
  133.     }
  134.     else if (y>BOX_BOT) {
  135.         top = BOX_BOT; bot = gr_max_y;
  136.     }
  137.     else if (y < (BOX_TOP - asi->h)) {
  138.         top = 0; bot = BOX_TOP;
  139.     }
  140.     spr_anim_set_limits(as, lef, top, rig, bot);
  141. }
  142.  
  143. /**********************************************************************
  144. * Change sprite limits so that the sprite will not enter the middle box
  145. **********************************************************************/
  146. WORD handle_x_limit(ANIM_SPRITE aspr, ANIM_SPR_INFO *asi)
  147. {
  148.     if (asi->x > 0 && asi->x < gr_max_x - asi->w
  149.         && (asi->y < BOX_TOP - asi->h || asi->y > BOX_BOT)) {
  150.         /** only change limits **/
  151.         set_limits(aspr, asi->x, asi->y);
  152.     }
  153.     else {  /** delete if bullet, otherwise bounce sprite from wall **/
  154.         if (asi->id==BULLET_ID || asi->id==EXPLO_ID)
  155.             return SPR_ANIM_FX_RET_DESTROY;
  156.         else {
  157.             if (asi->x > asi->rig)
  158.                 spr_anim_set_location(aspr, asi->rig, asi->y);
  159.             else 
  160.                 spr_anim_set_location(aspr, asi->lef, asi->y);
  161.             spr_anim_set_vector(aspr, -asi->dx, asi->dy);
  162.         }
  163.     }
  164.     return SPR_ANIM_FX_RET_RE_PUT;
  165. }
  166.  
  167. /**********************************************************************
  168. * Change sprite limits so that the sprite will not enter the middle box
  169. **********************************************************************/
  170. WORD handle_y_limit(ANIM_SPRITE aspr, ANIM_SPR_INFO *asi)
  171. {
  172.     if (asi->y > 0 && asi->y < gr_max_y - asi->h
  173.         && (asi->x < BOX_LEF - asi->w || asi->x > BOX_RIG)) {
  174.         /** only change limits **/
  175.         set_limits(aspr, asi->x, asi->y);
  176.     }
  177.     else {  /** delete if bullet, otherwise bounce sprite from wall **/
  178.         if (asi->id==BULLET_ID || asi->id==EXPLO_ID)
  179.             return SPR_ANIM_FX_RET_DESTROY;
  180.         else {
  181.             if (asi->y > asi->bot)
  182.                 spr_anim_set_location(aspr, asi->x, asi->bot);
  183.             else
  184.                 spr_anim_set_location(aspr, asi->x, asi->top);
  185.             spr_anim_set_vector(aspr, asi->dx, -asi->dy);
  186.         }
  187.     }
  188.     return SPR_ANIM_FX_RET_RE_PUT;
  189. }
  190.  
  191. /**********************************************************************
  192. * Creates how_many aliens
  193. **********************************************************************/
  194. void create_aliens(int how_many)
  195. {
  196.     int i,x,y;
  197.     ANIM_SPRITE alien;
  198.     
  199.     for (i = 0; i < how_many; i++) {
  200.         if ((alien=smspr_create_alien())==NULL)
  201.             break;
  202.         spr_anim_set_time(alien, 0, 5, alien_timeout + 10*i);
  203.             x = random(gr_max_x-40);
  204.             y = random(BOX_TOP-40);
  205.             if (random(2))
  206.                 y += BOX_BOT;
  207.         
  208.         spr_anim_set_location(alien, x,y);
  209.         set_limits(alien, x, y);
  210.         spr_anim_set_vector(alien, 
  211.                             alien_speed,
  212.                             alien_speed-(random(2*alien_speed-1)));
  213.         alien_count++;
  214.     }
  215.     alien_speed++;
  216. }    
  217.  
  218. /**********************************************************************
  219. * Initialize player into the left side of the screen 
  220. **********************************************************************/
  221. void init_player(void)
  222. {
  223.     int x,y;
  224.     
  225.     x = BOX_LEF/2;
  226.     y = (BOX_TOP+BOX_BOT)/2;
  227.     spr_anim_start(player);
  228.     spr_anim_set_location(player, x, y);
  229.     set_limits(player, x, y);
  230.     spr_anim_set_time(player, 0, 0, 0);
  231.     spr_anim_set_vector(player, 0,0);    
  232.     player_dying = player_dead = 0;
  233. }
  234.  
  235.  
  236. /**********************************************************************
  237. * Player collided with an alien.
  238. **********************************************************************/
  239. void kill_player(void)
  240. {
  241.     ANIM_SPRITE as;
  242.     ANIM_SPR_INFO *asi;
  243.     
  244.     asi = spr_anim_get_info(player);
  245.     spr_anim_stop(player);
  246.     player_dying = 1;
  247.     player_explosion = as = smspr_create_explosion();
  248.     if (as!=NULL) {
  249.         spr_anim_set_vector(as, asi->dx, asi->dy);
  250.         spr_anim_set_location(as, asi->x, asi->y);
  251.         set_limits(as, asi->x, asi->y);
  252.         spr_anim_set_time(as, 0,4,32);
  253.     }
  254.     else    /** weird, could not start an explosion. Kill player anyway **/
  255.         player_dead = 1;
  256. }
  257.  
  258. /**********************************************************************
  259. * Kill the given alien.
  260. **********************************************************************/
  261. void kill_alien(WORD w)
  262. {
  263.     ANIM_SPRITE as;
  264.     ANIM_SPR_INFO *asi;
  265.     
  266.     asi = spr_anim_get_info(aliens[w].as);
  267.     
  268.     spr_anim_delete(aliens[w].as);
  269.     aliens[w].as = NULL;
  270.     alien_count--;
  271.     
  272.     as = smspr_create_explosion();
  273.     if (as!=NULL) {
  274.         spr_anim_set_vector(as, asi->dx, asi->dy);
  275.         spr_anim_set_location(as, asi->x, asi->y);
  276.         set_limits(as, asi->x, asi->y);
  277.         spr_anim_set_time(as, 0,4,16);
  278.     }
  279. }
  280.  
  281. /**********************************************************************
  282. * The alien fx handler.
  283. **********************************************************************/
  284. WORD alien_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
  285. {
  286.     ANIM_SPR_INFO *asi;
  287.     WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
  288.  
  289.     asi = spr_anim_get_info(aspr);
  290.  
  291.     switch (fx) {
  292.         case SPR_ANIM_FX_TIMEOUT:  /* mark that the alien should be divided */
  293.             aliens[asi->id].divide = 1;
  294.             ret_code = SPR_ANIM_FX_RET_RE_PUT;  /** show it last time **/
  295.             break;
  296.             
  297.         case SPR_ANIM_FX_HIT_X_LIMIT:
  298.             ret_code = handle_x_limit(aspr, asi);
  299.             break;
  300.  
  301.         case SPR_ANIM_FX_HIT_Y_LIMIT:
  302.             ret_code = handle_y_limit(aspr, asi);
  303.             break;
  304.  
  305.         default:
  306.             sound(2000);delay(1000);nosound();    /** this is a bug **/
  307.             break;
  308.     }
  309.     return ret_code;
  310. }
  311.  
  312. /**********************************************************************
  313. * The player fx handler.
  314. **********************************************************************/
  315. WORD player_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
  316. {
  317.     ANIM_SPR_INFO *asi;
  318.     WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
  319.     WORD w;
  320.  
  321.     asi = spr_anim_get_info(aspr);
  322.  
  323.     switch (fx) {
  324.         case SPR_ANIM_FX_TIMEOUT:            
  325.             ret_code = SPR_ANIM_FX_RET_DELETE;
  326.             break;
  327.             
  328.         case SPR_ANIM_FX_HIT_X_LIMIT:
  329.             ret_code = handle_x_limit(aspr, asi);
  330.             break;
  331.  
  332.         case SPR_ANIM_FX_HIT_Y_LIMIT:
  333.             ret_code = handle_y_limit(aspr, asi);
  334.             break;
  335.  
  336.         case SPR_ANIM_FX_HIT_SPRITE:
  337.             w = spr_get_id(spr);
  338.             if (w<MAX_ALIEN) {
  339.                 kill_alien(w);
  340.                 if (!player_immune)
  341.                     kill_player();
  342.             }
  343.             break;
  344.             
  345.         default:
  346.             sound(2000);delay(1000);nosound();    /** this is a bug **/
  347.     }
  348.     return ret_code;    
  349. }
  350.  
  351. /**********************************************************************
  352. * The bullet fx handler.
  353. **********************************************************************/
  354. WORD bullet_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
  355. {
  356.     ANIM_SPR_INFO *asi;
  357.     WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
  358.     WORD w;
  359.  
  360.     asi = spr_anim_get_info(aspr);
  361.  
  362.     switch (fx) {
  363.         case SPR_ANIM_FX_TIMEOUT:
  364.             ret_code = SPR_ANIM_FX_RET_DESTROY;
  365.             break;
  366.             
  367.         case SPR_ANIM_FX_HIT_X_LIMIT:
  368.             ret_code = handle_x_limit(aspr, asi);
  369.             break;
  370.  
  371.         case SPR_ANIM_FX_HIT_Y_LIMIT:
  372.             ret_code = handle_y_limit(aspr, asi);
  373.             break;
  374.  
  375.         case SPR_ANIM_FX_HIT_SPRITE:
  376.             w = spr_get_id(spr);
  377.             if (w<MAX_ALIEN) {      /** kill alien **/
  378.                 inc_score(score_inc);
  379.                 kill_alien(w);
  380.                 ret_code = SPR_ANIM_FX_RET_DESTROY;
  381.             }
  382.             break;
  383.             
  384.         default:
  385.             sound(2000);delay(1000);nosound();    /** this is a bug **/
  386.     }
  387.     return ret_code;    
  388. }
  389.  
  390. /**********************************************************************
  391. * The explosion fx handler.
  392. **********************************************************************/
  393. WORD explo_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
  394. {
  395.     ANIM_SPR_INFO *asi;
  396.     WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
  397.  
  398.     asi = spr_anim_get_info(aspr);
  399.  
  400.     switch (fx) {
  401.         case SPR_ANIM_FX_TIMEOUT:
  402.             ret_code = SPR_ANIM_FX_RET_DESTROY;
  403.             break;
  404.             
  405.         case SPR_ANIM_FX_HIT_X_LIMIT:
  406.             ret_code = handle_x_limit(aspr, asi);
  407.             break;
  408.  
  409.         case SPR_ANIM_FX_HIT_Y_LIMIT:
  410.             ret_code = handle_y_limit(aspr, asi);
  411.             break;
  412.  
  413.         default:
  414.             sound(2000);delay(1000);nosound();    /** this is a bug **/
  415.     }
  416.     
  417.     if (ret_code == SPR_ANIM_FX_RET_DESTROY && aspr==player_explosion) {
  418.         player_explosion = NULL;
  419.         player_dead = 1;
  420.     }
  421.     return ret_code;    
  422. }
  423.  
  424.  
  425.  
  426. /**********************************************************************
  427. * Handle player input.
  428. * Return: 0 if game over, 1 otherwise.
  429. **********************************************************************/
  430. int handle_player(void)
  431. {
  432.     static int shot;
  433.     static int bullet_count = 0;
  434.     ANIM_SPR_INFO *asi;
  435.     ANIM_SPRITE as;
  436.  
  437.     if (gr_keys[GR_KEY_ESC])
  438.         return 0;
  439.     
  440.     if (!player_dying) {
  441.         shot = 0;
  442.         if (gr_keys[GR_KEY_Z] || gr_keys[GR_KEY_ARROW_LEFT]) {
  443.             asi = spr_anim_get_info(player);
  444.             asi->frame = (asi->frame+1)%16;
  445.             spr_anim_set_time(player, asi->frame, -1,-1);
  446.         }
  447.         if (gr_keys[GR_KEY_X] || gr_keys[GR_KEY_ARROW_RIGHT]){
  448.             asi = spr_anim_get_info(player);
  449.             asi->frame = (asi->frame-1)%16;
  450.             spr_anim_set_time(player, asi->frame, -1,-1);
  451.         }
  452.  
  453.         if (gr_keys[GR_KEY_M] || gr_keys[GR_KEY_ARROW_UP]) {
  454.             asi = spr_anim_get_info(player);
  455.             asi->dx += player_dirs[asi->frame].dx;
  456.             if (asi->dx > MAX_DX)
  457.                 asi->dx = MAX_DX;
  458.             if (asi->dx < -MAX_DX)
  459.                 asi->dx = -MAX_DX;
  460.             asi->dy += player_dirs[asi->frame].dy;
  461.             if (asi->dy > MAX_DY)
  462.                 asi->dy = MAX_DY;
  463.             if (asi->dy < -MAX_DY)
  464.                 asi->dy = -MAX_DY;
  465.             spr_anim_set_vector(player, asi->dx, asi->dy);
  466.         }
  467.         
  468.         if (gr_keys[GR_KEY_SPACE] 
  469.             || gr_keys[GR_KEY_COMMA]
  470.             || gr_keys[GR_KEY_DOT]) {
  471.             shot = 1;
  472.             bullet_count++;
  473.             if (bullet_count<6) {
  474.                 asi = spr_anim_get_info(player);
  475.                 as = smspr_create_bullet();
  476.                 if (as!=NULL) {
  477.                     asi->dx = player_dirs[asi->frame].dx*4;
  478.                     asi->dy = player_dirs[asi->frame].dy*4;
  479.                     asi->x = asi->x + asi->w/2;
  480.                     asi->y = asi->y + asi->h/2;
  481.                     spr_anim_set_vector(as, asi->dx, asi->dy);
  482.                     spr_anim_set_location(as, asi->x, asi->y);
  483.                     set_limits(as, asi->x, asi->y);
  484.                     spr_anim_set_time(as, 0,0,0);
  485.                 }
  486.             }
  487.         }
  488.  
  489.         if (!shot)
  490.             bullet_count = 0;
  491.     }
  492.     
  493.     if (player_dead) {
  494.         dec_lives();
  495.         if (lives>0) {
  496.             player_dead = player_dying = 0;
  497.             player_immune = 15; /** player is invincible for 15 frames **/
  498.             spr_anim_start(player);
  499.             spr_anim_set_vector(player,0,0);
  500.             delay(200);
  501.         }
  502.     }
  503.     if (player_immune>0)
  504.         player_immune--;
  505.     
  506.     return (lives>0);
  507. }
  508.  
  509.  
  510. /**********************************************************************
  511. * Handle new wave generation, player death etc special events which
  512. * must be done after spr_anim_next_pass()
  513. **********************************************************************/
  514. void handle_advancement(void)
  515. {
  516.     ANIM_SPRITE as[4];
  517.     ANIM_SPR_INFO *asi;
  518.     int i;
  519.  
  520.     /** Divide the marked aliens into four new aliens **/
  521.     for (i=0; i<MAX_ALIEN; i++) {
  522.         if (aliens[i].divide) {
  523.             aliens[i].divide = 0;
  524.             if (aliens[i].as!=NULL) {
  525.                 asi = spr_anim_get_info(aliens[i].as);
  526.                 spr_anim_delete(aliens[i].as);
  527.                 aliens[i].as = NULL;
  528.                 alien_count--;
  529.                 for (i=0; i<4; i++) {
  530.                     as[i] = smspr_create_alien();
  531.                     if (as[i]!=NULL) {
  532.                         spr_anim_set_location(as[i], asi->x,asi->y);
  533.                         spr_anim_set_time(as[i], 0, 4, alien_timeout);
  534.                         set_limits(as[i], asi->x, asi->y);
  535.                         alien_count++;
  536.                     }
  537.                 }
  538.                 if (as[0]!=NULL)
  539.                     spr_anim_set_vector(as[0],  alien_speed, alien_speed);
  540.                 if (as[1]!=NULL)
  541.                     spr_anim_set_vector(as[1], -alien_speed, alien_speed);
  542.                 if (as[2]!=NULL)
  543.                     spr_anim_set_vector(as[2],  alien_speed,-alien_speed);
  544.                 if (as[3]!=NULL)
  545.                     spr_anim_set_vector(as[3], -alien_speed,-alien_speed);
  546.  
  547.             }
  548.         }
  549.     }        
  550.     /** start the next alien wave if all aliens killed **/
  551.     if (alien_count<=0) {
  552.         alien_count = 0;
  553.         for (i=1; i<50; i++) {
  554.             setactivepage(spr_anim_next_pass()^1);
  555.             spr_regulate_speed();         
  556.             gr_xy_printf(NEXT_WAVE_X, NEXT_WAVE_Y, NEXT_WAVE1, bonus);
  557.             setactivepage(spr_anim_next_pass()^1);
  558.             spr_regulate_speed();         
  559.             gr_xy_printf(NEXT_WAVE_X, NEXT_WAVE_Y, NEXT_WAVE2, bonus);
  560.         }
  561.         if (max_aliens<MAX_ALIEN-2)
  562.             max_aliens += 2;
  563.         if (alien_timeout > 100)
  564.             alien_timeout = (4*alien_timeout)/3;
  565.         create_aliens(max_aliens);
  566.         init_player();
  567.         inc_score(bonus);
  568.         score_inc *= 2;
  569.         bonus = max_aliens*300;
  570.         gr_dual_xy_printf(NEXT_WAVE_X, NEXT_WAVE_Y, NEXT_WAVE_CLEAR);
  571.     }
  572.     if (bonus>0)
  573.         bonus--;
  574. }
  575.  
  576. /**********************************************************************
  577. * Initializes the game. (Variables, background, aliens, player)
  578. * Return: Player sprite if all OK, NULL otherwise.
  579. **********************************************************************/
  580. ANIM_SPRITE game_initialize(void)
  581. {
  582.     /** global variables **/
  583.     player_dead = player_immune = player_dying = 0;
  584.     score = 0;
  585.     score_inc = 5;
  586.     bonus = 2000;
  587.     lives = 5;
  588.         
  589.     /*** background ***/
  590.     setactivepage(0);
  591.     setfillstyle(EMPTY_FILL, 0);
  592.     bar(BOX_LEF, BOX_TOP,  BOX_RIG, BOX_BOT);
  593.     rectangle(BOX_LEF, BOX_TOP,  BOX_RIG, BOX_BOT);
  594.     setactivepage(1);
  595.     setfillstyle(EMPTY_FILL, 0);
  596.     bar(BOX_LEF, BOX_TOP,  BOX_RIG, BOX_BOT);
  597.     rectangle(BOX_LEF, BOX_TOP,  BOX_RIG, BOX_BOT);
  598.     
  599.     gr_dual_xy_printf(STARMINES_X, STARMINES_Y, STARMINES);
  600.     gr_dual_xy_printf(COPYRIGHT_X, COPYRIGHT_Y, COPYRIGHT);
  601.     gr_dual_xy_printf(LIVES_X, LIVES_Y, "LIVES %d", lives);
  602.     gr_dual_xy_printf(SCORE_X, SCORE_Y, "SCORE %06d", score);
  603.  
  604.     /*** standard aliens ***/
  605.     alien_count = 0;
  606.     alien_timeout = 400;
  607.     alien_speed = 2;
  608.     max_aliens = MAX_ALIEN/10;
  609.     create_aliens(max_aliens);
  610.  
  611.     /*** the player if necessary ***/
  612.     if (player==NULL)
  613.         player = smspr_create_player();
  614.     if (player==NULL)
  615.         return NULL;
  616.     
  617.     init_player();
  618.     
  619.     return player;
  620. }
  621.  
  622. /**********************************************************************
  623. * Game over text. Wait for a keypress. Init new game or exit.
  624. **********************************************************************/
  625. void game_over(void)
  626. {
  627.     int i;
  628.     gr_dual_xy_printf(GAME_OVER_X, GAME_OVER_Y, GAME_OVER);
  629.     gr_dual_xy_printf(GAME_OVER2_X, GAME_OVER2_Y, GAME_OVER2);
  630.     i = 0;
  631.     if (player_dead) {
  632.         do {
  633.             spr_anim_next_pass();
  634.             spr_regulate_speed();
  635.             delay(10);
  636.             i = gr_inkey();
  637.         } while (i!=27 && i!=' ');
  638.     }
  639.     if (i==27 || !player_dead)
  640.         exit(0);
  641.     else {  /** kill surviving aliens **/
  642.         for (i=0; i<MAX_ALIEN; i++)
  643.             if (aliens[i].as!=NULL) {
  644.                 spr_anim_delete(aliens[i].as);
  645.                 aliens[i].as = NULL;
  646.             }
  647.         game_initialize();
  648.     }
  649.     
  650. }
  651.  
  652. /** farcore for saving background of MAX_ALIEN 2-frame aliens,  **/
  653. /** 16 player shapes, 50 bullets and 20 4-frame explosions.     **/
  654. #define MEM_NEEDED (80L*2*MAX_ALIEN*2 + \
  655.                     96L*(sprite_resolution*2+2)*16 + \
  656.                     8L*2*50 + \
  657.                     120L*2*20*4)
  658.  
  659. /**********************************************************************
  660. * The main program
  661. **********************************************************************/
  662. void main(int argc, char **argv)
  663. {
  664.     int i,j;
  665.     
  666.     puts("StarMines - a sprite toolkit demonstration game");
  667.     puts("      Copyright (C) 1990 Jari Karjala\n");
  668.     
  669.     if (argc>1)
  670.         sprite_resolution = atoi(argv[1]);
  671.  
  672.     if (argc>2)  /** watch out for those leaks **/
  673.         printf("core %ld, farcore %ld", (long)coreleft(), farcoreleft());
  674.     
  675.     if (farcoreleft() < MEM_NEEDED) {
  676.         printf("Not enough memory (%d kB needed), sorry!", 
  677.                90 + MEM_NEEDED/1024L);
  678.         exit(5);
  679.     }
  680.     
  681.     gr_detect(GR_TYPE_SPR, &i, &j);
  682.     if (i == -1) {
  683.         puts("Unsupported graphics mode, sorry!");
  684.         exit(10);
  685.     }
  686.     gr_start(&i, &j);
  687.     spr_initialize(i);
  688.     
  689.     if (game_initialize()==NULL) {
  690.         gr_dual_xy_printf(0,0,"Initialization failed, press enter...");
  691.         while(gr_inkey()==0)
  692.             ;
  693.         exit(20);
  694.     }
  695.  
  696.     while (1) {
  697.         i = 1;
  698.         gr_start_kbd_grab();    /** grab keyboard, gr_inkey won't work **/
  699.         while (i) {
  700.             spr_anim_next_pass();
  701.             spr_regulate_speed();
  702.             handle_advancement();
  703.             i = handle_player();
  704.             if (argc>2) {   /** watch out for those leaks **/
  705.                 gr_gotoxy(1,1);
  706.                 gr_printf("%ld %ld  ", (long)coreleft(), farcoreleft());
  707.             }
  708.         }
  709.         gr_end_kbd_grab();    /** gr_inkey works again **/
  710.         game_over();
  711.     }
  712. }
  713.