home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * sm.c
- *
- * StarMines - a sprite toolkit demonstration game.
- *
- * Compile with the following command line:
- *
- * tcc -ms sm.c smspr.c stks.lib graphics.lib
- *
- **********************************************************************
- This file is part of
-
- STK -- The sprite toolkit -- version 1.0
-
- Copyright (C) Jari Karjala 1990
-
- The sprite toolkit (STK) is a FreeWare toolkit for creating high
- resolution sprite graphics with PCompatible hardware. This toolkit
- is provided as is without any warranty or such thing. See the file
- COPYING for further information.
-
- **********************************************************************
- **********************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <alloc.h>
- #include <dos.h>
- #include <graphics.h>
-
- #include "stk.h"
-
- #include "sm.h"
- #include "smspr.h"
-
- int sprite_resolution = 8;
- ALIEN_TYPE aliens[MAX_ALIEN] = { NULL };
- ANIM_SPRITE player = NULL;
- ANIM_SPRITE player_explosion = NULL;
-
- int player_dying; /** non-zero when player is exploding **/
- int player_dead; /** non-zero when player has exploded **/
- int player_immune; /** non-zero when player is invincible **/
-
- int lives; /** number of lives **/
- long int score; /** current score **/
- int score_inc; /** score increment **/
- int bonus; /** bonus after wave **/
-
- int alien_count; /** number of aliens alive **/
- int max_aliens; /** initial number of aliens **/
- int alien_timeout; /** timeout before divide **/
- int alien_speed; /** alien speed **/
-
- struct dir_struc {
- int dx,dy;
- };
- struct dir_struc player_dirs[16] = {
- 2,0, 2,-1, 2,-2, 1,-2, 0,-2, -1,-2, -2,-2, -2, -1,
- -2,0, -2,1, -2,2, -1,2, 0,2, 1,2, 2,2, 2,1
- };
-
- #define MAX_DX 8
- #define MAX_DY 6
-
- #define STARMINES "StarMines"
- #define STARMINES_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 - (8*strlen(STARMINES))/2)
- #define STARMINES_Y (BOX_TOP+12)
-
- #define COPYRIGHT "Copyright (C) J.Karjala 1990"
- #define COPYRIGHT_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 - (8*strlen(COPYRIGHT))/2)
- #define COPYRIGHT_Y (BOX_BOT-16)
-
- #define GAME_OVER "*** GAME OVER ***"
- #define GAME_OVER_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 - (8*strlen(GAME_OVER))/2)
- #define GAME_OVER_Y (BOX_BOT-45)
- #define GAME_OVER2 "Press SPACE to start"
- #define GAME_OVER2_X (BOX_LEF + (BOX_RIG-BOX_LEF)/2 -(8*strlen(GAME_OVER2))/2)
- #define GAME_OVER2_Y (BOX_BOT-35)
-
- #define NEXT_WAVE1 "+*+ BONUS %05d +*+"
- #define NEXT_WAVE2 "*+* BONUS %05d *+*"
- #define NEXT_WAVE_CLEAR " "
- #define NEXT_WAVE_X (BOX_LEF +(BOX_RIG-BOX_LEF)/2 -(8*strlen(NEXT_WAVE1)+1)/2)
- #define NEXT_WAVE_Y (BOX_BOT-40)
-
- #define SCORE_X (BOX_LEF+20)
- #define SCORE_Y (BOX_TOP+40)
- #define LIVES_X (BOX_RIG-20-8*8)
- #define LIVES_Y (BOX_TOP+40)
-
-
- /**********************************************************************
- * Increment the score by i and display it
- **********************************************************************/
- void inc_score(int i)
- {
- score += (long)i;
- gr_dual_xy_printf(SCORE_X, SCORE_Y, "SCORE %06ld", score);
- }
- /**********************************************************************
- * Decrement lives
- **********************************************************************/
- void dec_lives(void)
- {
- if (lives>0)
- lives--;
-
- gr_dual_xy_printf(LIVES_X, LIVES_Y, "LIVES %d", lives);
- }
-
-
- /**********************************************************************
- * Set new limits for the given sprite at position x,y
- **********************************************************************/
- void set_limits(ANIM_SPRITE as, int x, int y)
- {
- ANIM_SPR_INFO *asi;
- int top, bot, lef, rig;
-
- asi = spr_anim_get_info(as);
-
- lef = 0; rig = gr_max_x;
- top = 0; bot = gr_max_y;
-
- if (x>BOX_RIG) {
- lef = BOX_RIG; rig = gr_max_x;
- }
- else if (x < (BOX_LEF - asi->w)) {
- lef = 0; rig = BOX_LEF;
- }
- else if (y>BOX_BOT) {
- top = BOX_BOT; bot = gr_max_y;
- }
- else if (y < (BOX_TOP - asi->h)) {
- top = 0; bot = BOX_TOP;
- }
- spr_anim_set_limits(as, lef, top, rig, bot);
- }
-
- /**********************************************************************
- * Change sprite limits so that the sprite will not enter the middle box
- **********************************************************************/
- WORD handle_x_limit(ANIM_SPRITE aspr, ANIM_SPR_INFO *asi)
- {
- if (asi->x > 0 && asi->x < gr_max_x - asi->w
- && (asi->y < BOX_TOP - asi->h || asi->y > BOX_BOT)) {
- /** only change limits **/
- set_limits(aspr, asi->x, asi->y);
- }
- else { /** delete if bullet, otherwise bounce sprite from wall **/
- if (asi->id==BULLET_ID || asi->id==EXPLO_ID)
- return SPR_ANIM_FX_RET_DESTROY;
- else {
- if (asi->x > asi->rig)
- spr_anim_set_location(aspr, asi->rig, asi->y);
- else
- spr_anim_set_location(aspr, asi->lef, asi->y);
- spr_anim_set_vector(aspr, -asi->dx, asi->dy);
- }
- }
- return SPR_ANIM_FX_RET_RE_PUT;
- }
-
- /**********************************************************************
- * Change sprite limits so that the sprite will not enter the middle box
- **********************************************************************/
- WORD handle_y_limit(ANIM_SPRITE aspr, ANIM_SPR_INFO *asi)
- {
- if (asi->y > 0 && asi->y < gr_max_y - asi->h
- && (asi->x < BOX_LEF - asi->w || asi->x > BOX_RIG)) {
- /** only change limits **/
- set_limits(aspr, asi->x, asi->y);
- }
- else { /** delete if bullet, otherwise bounce sprite from wall **/
- if (asi->id==BULLET_ID || asi->id==EXPLO_ID)
- return SPR_ANIM_FX_RET_DESTROY;
- else {
- if (asi->y > asi->bot)
- spr_anim_set_location(aspr, asi->x, asi->bot);
- else
- spr_anim_set_location(aspr, asi->x, asi->top);
- spr_anim_set_vector(aspr, asi->dx, -asi->dy);
- }
- }
- return SPR_ANIM_FX_RET_RE_PUT;
- }
-
- /**********************************************************************
- * Creates how_many aliens
- **********************************************************************/
- void create_aliens(int how_many)
- {
- int i,x,y;
- ANIM_SPRITE alien;
-
- for (i = 0; i < how_many; i++) {
- if ((alien=smspr_create_alien())==NULL)
- break;
- spr_anim_set_time(alien, 0, 5, alien_timeout + 10*i);
- x = random(gr_max_x-40);
- y = random(BOX_TOP-40);
- if (random(2))
- y += BOX_BOT;
-
- spr_anim_set_location(alien, x,y);
- set_limits(alien, x, y);
- spr_anim_set_vector(alien,
- alien_speed,
- alien_speed-(random(2*alien_speed-1)));
- alien_count++;
- }
- alien_speed++;
- }
-
- /**********************************************************************
- * Initialize player into the left side of the screen
- **********************************************************************/
- void init_player(void)
- {
- int x,y;
-
- x = BOX_LEF/2;
- y = (BOX_TOP+BOX_BOT)/2;
- spr_anim_start(player);
- spr_anim_set_location(player, x, y);
- set_limits(player, x, y);
- spr_anim_set_time(player, 0, 0, 0);
- spr_anim_set_vector(player, 0,0);
- player_dying = player_dead = 0;
- }
-
-
- /**********************************************************************
- * Player collided with an alien.
- **********************************************************************/
- void kill_player(void)
- {
- ANIM_SPRITE as;
- ANIM_SPR_INFO *asi;
-
- asi = spr_anim_get_info(player);
- spr_anim_stop(player);
- player_dying = 1;
- player_explosion = as = smspr_create_explosion();
- if (as!=NULL) {
- spr_anim_set_vector(as, asi->dx, asi->dy);
- spr_anim_set_location(as, asi->x, asi->y);
- set_limits(as, asi->x, asi->y);
- spr_anim_set_time(as, 0,4,32);
- }
- else /** weird, could not start an explosion. Kill player anyway **/
- player_dead = 1;
- }
-
- /**********************************************************************
- * Kill the given alien.
- **********************************************************************/
- void kill_alien(WORD w)
- {
- ANIM_SPRITE as;
- ANIM_SPR_INFO *asi;
-
- asi = spr_anim_get_info(aliens[w].as);
-
- spr_anim_delete(aliens[w].as);
- aliens[w].as = NULL;
- alien_count--;
-
- as = smspr_create_explosion();
- if (as!=NULL) {
- spr_anim_set_vector(as, asi->dx, asi->dy);
- spr_anim_set_location(as, asi->x, asi->y);
- set_limits(as, asi->x, asi->y);
- spr_anim_set_time(as, 0,4,16);
- }
- }
-
- /**********************************************************************
- * The alien fx handler.
- **********************************************************************/
- WORD alien_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
- {
- ANIM_SPR_INFO *asi;
- WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
-
- asi = spr_anim_get_info(aspr);
-
- switch (fx) {
- case SPR_ANIM_FX_TIMEOUT: /* mark that the alien should be divided */
- aliens[asi->id].divide = 1;
- ret_code = SPR_ANIM_FX_RET_RE_PUT; /** show it last time **/
- break;
-
- case SPR_ANIM_FX_HIT_X_LIMIT:
- ret_code = handle_x_limit(aspr, asi);
- break;
-
- case SPR_ANIM_FX_HIT_Y_LIMIT:
- ret_code = handle_y_limit(aspr, asi);
- break;
-
- default:
- sound(2000);delay(1000);nosound(); /** this is a bug **/
- break;
- }
- return ret_code;
- }
-
- /**********************************************************************
- * The player fx handler.
- **********************************************************************/
- WORD player_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
- {
- ANIM_SPR_INFO *asi;
- WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
- WORD w;
-
- asi = spr_anim_get_info(aspr);
-
- switch (fx) {
- case SPR_ANIM_FX_TIMEOUT:
- ret_code = SPR_ANIM_FX_RET_DELETE;
- break;
-
- case SPR_ANIM_FX_HIT_X_LIMIT:
- ret_code = handle_x_limit(aspr, asi);
- break;
-
- case SPR_ANIM_FX_HIT_Y_LIMIT:
- ret_code = handle_y_limit(aspr, asi);
- break;
-
- case SPR_ANIM_FX_HIT_SPRITE:
- w = spr_get_id(spr);
- if (w<MAX_ALIEN) {
- kill_alien(w);
- if (!player_immune)
- kill_player();
- }
- break;
-
- default:
- sound(2000);delay(1000);nosound(); /** this is a bug **/
- }
- return ret_code;
- }
-
- /**********************************************************************
- * The bullet fx handler.
- **********************************************************************/
- WORD bullet_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
- {
- ANIM_SPR_INFO *asi;
- WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
- WORD w;
-
- asi = spr_anim_get_info(aspr);
-
- switch (fx) {
- case SPR_ANIM_FX_TIMEOUT:
- ret_code = SPR_ANIM_FX_RET_DESTROY;
- break;
-
- case SPR_ANIM_FX_HIT_X_LIMIT:
- ret_code = handle_x_limit(aspr, asi);
- break;
-
- case SPR_ANIM_FX_HIT_Y_LIMIT:
- ret_code = handle_y_limit(aspr, asi);
- break;
-
- case SPR_ANIM_FX_HIT_SPRITE:
- w = spr_get_id(spr);
- if (w<MAX_ALIEN) { /** kill alien **/
- inc_score(score_inc);
- kill_alien(w);
- ret_code = SPR_ANIM_FX_RET_DESTROY;
- }
- break;
-
- default:
- sound(2000);delay(1000);nosound(); /** this is a bug **/
- }
- return ret_code;
- }
-
- /**********************************************************************
- * The explosion fx handler.
- **********************************************************************/
- WORD explo_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
- {
- ANIM_SPR_INFO *asi;
- WORD ret_code = SPR_ANIM_FX_RET_NOTHING;
-
- asi = spr_anim_get_info(aspr);
-
- switch (fx) {
- case SPR_ANIM_FX_TIMEOUT:
- ret_code = SPR_ANIM_FX_RET_DESTROY;
- break;
-
- case SPR_ANIM_FX_HIT_X_LIMIT:
- ret_code = handle_x_limit(aspr, asi);
- break;
-
- case SPR_ANIM_FX_HIT_Y_LIMIT:
- ret_code = handle_y_limit(aspr, asi);
- break;
-
- default:
- sound(2000);delay(1000);nosound(); /** this is a bug **/
- }
-
- if (ret_code == SPR_ANIM_FX_RET_DESTROY && aspr==player_explosion) {
- player_explosion = NULL;
- player_dead = 1;
- }
- return ret_code;
- }
-
-
-
- /**********************************************************************
- * Handle player input.
- * Return: 0 if game over, 1 otherwise.
- **********************************************************************/
- int handle_player(void)
- {
- static int shot;
- static int bullet_count = 0;
- ANIM_SPR_INFO *asi;
- ANIM_SPRITE as;
-
- if (gr_keys[GR_KEY_ESC])
- return 0;
-
- if (!player_dying) {
- shot = 0;
- if (gr_keys[GR_KEY_Z] || gr_keys[GR_KEY_ARROW_LEFT]) {
- asi = spr_anim_get_info(player);
- asi->frame = (asi->frame+1)%16;
- spr_anim_set_time(player, asi->frame, -1,-1);
- }
- if (gr_keys[GR_KEY_X] || gr_keys[GR_KEY_ARROW_RIGHT]){
- asi = spr_anim_get_info(player);
- asi->frame = (asi->frame-1)%16;
- spr_anim_set_time(player, asi->frame, -1,-1);
- }
-
- if (gr_keys[GR_KEY_M] || gr_keys[GR_KEY_ARROW_UP]) {
- asi = spr_anim_get_info(player);
- asi->dx += player_dirs[asi->frame].dx;
- if (asi->dx > MAX_DX)
- asi->dx = MAX_DX;
- if (asi->dx < -MAX_DX)
- asi->dx = -MAX_DX;
- asi->dy += player_dirs[asi->frame].dy;
- if (asi->dy > MAX_DY)
- asi->dy = MAX_DY;
- if (asi->dy < -MAX_DY)
- asi->dy = -MAX_DY;
- spr_anim_set_vector(player, asi->dx, asi->dy);
- }
-
- if (gr_keys[GR_KEY_SPACE]
- || gr_keys[GR_KEY_COMMA]
- || gr_keys[GR_KEY_DOT]) {
- shot = 1;
- bullet_count++;
- if (bullet_count<6) {
- asi = spr_anim_get_info(player);
- as = smspr_create_bullet();
- if (as!=NULL) {
- asi->dx = player_dirs[asi->frame].dx*4;
- asi->dy = player_dirs[asi->frame].dy*4;
- asi->x = asi->x + asi->w/2;
- asi->y = asi->y + asi->h/2;
- spr_anim_set_vector(as, asi->dx, asi->dy);
- spr_anim_set_location(as, asi->x, asi->y);
- set_limits(as, asi->x, asi->y);
- spr_anim_set_time(as, 0,0,0);
- }
- }
- }
-
- if (!shot)
- bullet_count = 0;
- }
-
- if (player_dead) {
- dec_lives();
- if (lives>0) {
- player_dead = player_dying = 0;
- player_immune = 15; /** player is invincible for 15 frames **/
- spr_anim_start(player);
- spr_anim_set_vector(player,0,0);
- delay(200);
- }
- }
- if (player_immune>0)
- player_immune--;
-
- return (lives>0);
- }
-
-
- /**********************************************************************
- * Handle new wave generation, player death etc special events which
- * must be done after spr_anim_next_pass()
- **********************************************************************/
- void handle_advancement(void)
- {
- ANIM_SPRITE as[4];
- ANIM_SPR_INFO *asi;
- int i;
-
- /** Divide the marked aliens into four new aliens **/
- for (i=0; i<MAX_ALIEN; i++) {
- if (aliens[i].divide) {
- aliens[i].divide = 0;
- if (aliens[i].as!=NULL) {
- asi = spr_anim_get_info(aliens[i].as);
- spr_anim_delete(aliens[i].as);
- aliens[i].as = NULL;
- alien_count--;
- for (i=0; i<4; i++) {
- as[i] = smspr_create_alien();
- if (as[i]!=NULL) {
- spr_anim_set_location(as[i], asi->x,asi->y);
- spr_anim_set_time(as[i], 0, 4, alien_timeout);
- set_limits(as[i], asi->x, asi->y);
- alien_count++;
- }
- }
- if (as[0]!=NULL)
- spr_anim_set_vector(as[0], alien_speed, alien_speed);
- if (as[1]!=NULL)
- spr_anim_set_vector(as[1], -alien_speed, alien_speed);
- if (as[2]!=NULL)
- spr_anim_set_vector(as[2], alien_speed,-alien_speed);
- if (as[3]!=NULL)
- spr_anim_set_vector(as[3], -alien_speed,-alien_speed);
-
- }
- }
- }
- /** start the next alien wave if all aliens killed **/
- if (alien_count<=0) {
- alien_count = 0;
- for (i=1; i<50; i++) {
- setactivepage(spr_anim_next_pass()^1);
- spr_regulate_speed();
- gr_xy_printf(NEXT_WAVE_X, NEXT_WAVE_Y, NEXT_WAVE1, bonus);
- setactivepage(spr_anim_next_pass()^1);
- spr_regulate_speed();
- gr_xy_printf(NEXT_WAVE_X, NEXT_WAVE_Y, NEXT_WAVE2, bonus);
- }
- if (max_aliens<MAX_ALIEN-2)
- max_aliens += 2;
- if (alien_timeout > 100)
- alien_timeout = (4*alien_timeout)/3;
- create_aliens(max_aliens);
- init_player();
- inc_score(bonus);
- score_inc *= 2;
- bonus = max_aliens*300;
- gr_dual_xy_printf(NEXT_WAVE_X, NEXT_WAVE_Y, NEXT_WAVE_CLEAR);
- }
- if (bonus>0)
- bonus--;
- }
-
- /**********************************************************************
- * Initializes the game. (Variables, background, aliens, player)
- * Return: Player sprite if all OK, NULL otherwise.
- **********************************************************************/
- ANIM_SPRITE game_initialize(void)
- {
- /** global variables **/
- player_dead = player_immune = player_dying = 0;
- score = 0;
- score_inc = 5;
- bonus = 2000;
- lives = 5;
-
- /*** background ***/
- setactivepage(0);
- setfillstyle(EMPTY_FILL, 0);
- bar(BOX_LEF, BOX_TOP, BOX_RIG, BOX_BOT);
- rectangle(BOX_LEF, BOX_TOP, BOX_RIG, BOX_BOT);
- setactivepage(1);
- setfillstyle(EMPTY_FILL, 0);
- bar(BOX_LEF, BOX_TOP, BOX_RIG, BOX_BOT);
- rectangle(BOX_LEF, BOX_TOP, BOX_RIG, BOX_BOT);
-
- gr_dual_xy_printf(STARMINES_X, STARMINES_Y, STARMINES);
- gr_dual_xy_printf(COPYRIGHT_X, COPYRIGHT_Y, COPYRIGHT);
- gr_dual_xy_printf(LIVES_X, LIVES_Y, "LIVES %d", lives);
- gr_dual_xy_printf(SCORE_X, SCORE_Y, "SCORE %06d", score);
-
- /*** standard aliens ***/
- alien_count = 0;
- alien_timeout = 400;
- alien_speed = 2;
- max_aliens = MAX_ALIEN/10;
- create_aliens(max_aliens);
-
- /*** the player if necessary ***/
- if (player==NULL)
- player = smspr_create_player();
- if (player==NULL)
- return NULL;
-
- init_player();
-
- return player;
- }
-
- /**********************************************************************
- * Game over text. Wait for a keypress. Init new game or exit.
- **********************************************************************/
- void game_over(void)
- {
- int i;
- gr_dual_xy_printf(GAME_OVER_X, GAME_OVER_Y, GAME_OVER);
- gr_dual_xy_printf(GAME_OVER2_X, GAME_OVER2_Y, GAME_OVER2);
- i = 0;
- if (player_dead) {
- do {
- spr_anim_next_pass();
- spr_regulate_speed();
- delay(10);
- i = gr_inkey();
- } while (i!=27 && i!=' ');
- }
- if (i==27 || !player_dead)
- exit(0);
- else { /** kill surviving aliens **/
- for (i=0; i<MAX_ALIEN; i++)
- if (aliens[i].as!=NULL) {
- spr_anim_delete(aliens[i].as);
- aliens[i].as = NULL;
- }
- game_initialize();
- }
-
- }
-
- /** farcore for saving background of MAX_ALIEN 2-frame aliens, **/
- /** 16 player shapes, 50 bullets and 20 4-frame explosions. **/
- #define MEM_NEEDED (80L*2*MAX_ALIEN*2 + \
- 96L*(sprite_resolution*2+2)*16 + \
- 8L*2*50 + \
- 120L*2*20*4)
-
- /**********************************************************************
- * The main program
- **********************************************************************/
- void main(int argc, char **argv)
- {
- int i,j;
-
- puts("StarMines - a sprite toolkit demonstration game");
- puts(" Copyright (C) 1990 Jari Karjala\n");
-
- if (argc>1)
- sprite_resolution = atoi(argv[1]);
-
- if (argc>2) /** watch out for those leaks **/
- printf("core %ld, farcore %ld", (long)coreleft(), farcoreleft());
-
- if (farcoreleft() < MEM_NEEDED) {
- printf("Not enough memory (%d kB needed), sorry!",
- 90 + MEM_NEEDED/1024L);
- exit(5);
- }
-
- gr_detect(GR_TYPE_SPR, &i, &j);
- if (i == -1) {
- puts("Unsupported graphics mode, sorry!");
- exit(10);
- }
- gr_start(&i, &j);
- spr_initialize(i);
-
- if (game_initialize()==NULL) {
- gr_dual_xy_printf(0,0,"Initialization failed, press enter...");
- while(gr_inkey()==0)
- ;
- exit(20);
- }
-
- while (1) {
- i = 1;
- gr_start_kbd_grab(); /** grab keyboard, gr_inkey won't work **/
- while (i) {
- spr_anim_next_pass();
- spr_regulate_speed();
- handle_advancement();
- i = handle_player();
- if (argc>2) { /** watch out for those leaks **/
- gr_gotoxy(1,1);
- gr_printf("%ld %ld ", (long)coreleft(), farcoreleft());
- }
- }
- gr_end_kbd_grab(); /** gr_inkey works again **/
- game_over();
- }
- }
-