home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * sm.c
- *
- * StarMines - a sprite toolkit demonstration game.
- *
- * Compile & link with the following command line:
- * tcc -ms sm.c smspr.c smscores.c stks.lib graphics.lib
- *
- * (The sprite map files must be in the "smp" subdirectory)
- **********************************************************************
- This file is part of
-
- STK -- The sprite toolkit -- version 1.1
-
- Copyright (C) Jari Karjala 1991
-
- 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>
-
- extern unsigned _stklen = 8192;
-
- #include "stk.h"
-
- #include "sm.h"
- #include "smspr.h"
- #include "smscores.h"
-
- #define MAX_BULLET 20
-
- int sprite_resolution = 8;
- ALIEN_TYPE aliens[MAX_ALIEN];
- EXPL_TYPE expls[MAX_EXPL];
- ANIM_SPRITE player = NULL;
- ANIM_SPRITE player_explosion;
- SCORE_ENTRY se;
-
- 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 bullets_flying; /** number of bullets in the air **/
-
- int wave; /** the current alien wave **/
- int max_aliens; /** initial number of aliens in one wave **/
- int alien_count; /** number of aliens alive currently **/
- int alien_timeout; /** timeout before divide alien **/
- int alien_speed; /** alien speed **/
-
- int cheat_wave=0; /** the starting wave when cheating **/
-
- struct dir_struct {
- int dx,dy;
- };
- /** Deltas for each possible player movement direction (clockwise order) **/
- struct dir_struct 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
- };
- /** Deltas from ship coordinates to the missile initial position **/
- struct dir_struct missile_deltas[16] = {
- 17,10, 17,7, 15,4, 12,2, 8,1, 5,1, 2,3, 0,6,
- -1,10, -1,13, 1,16, 4,18, 8,19, 11,19, 14,17, 16,14
- };
- /** Initial mine directions **/
- struct dir_struct mine_dir[4] = { 1,1, -1,-1, -1,1, 1,-1 };
-
- /** Maximum player X and Y velocities **/
- #define MAX_DX 10
- #define MAX_DY 8
-
- /** After this many waves shot effects change. If you increase this, **/
- /** some waves may become impossible to pass. See handle_advancement.**/
- #define HIT_DIVIDES_LIM 4
-
-
- #define HISCORE "The StarMines Hall of Fame:"
- #define HISCORE2 " Give your name, please: "
- #define HISCORE3 "%-18.18s %06ld"
- #define HISCORE_X ((BOX_LEF +(BOX_RIG -BOX_LEF -8*strlen(HISCORE))/2)&0xFF8)
- #define HISCORE_Y (BOX_TOP+10)
-
- #define HISCORES_X ((BOX_LEF+(BOX_RIG-BOX_LEF-25*8)/2)&0xFF8)
- #define HISCORES_Y (BOX_TOP+25)
-
- #define STARMINES "StarMines"
- #define STARMINES_Y (BOX_TOP+12)
-
- #define COPYRIGHT " Copyright 1991 J.Karjala"
- #define COPYRIGHT_Y (BOX_BOT-15)
-
- #define GAME_OVER2 "Press SPACE to restart"
- #define GAME_OVER2_Y (BOX_BOT-20)
- #define GAME_OVER3 "or Esc to exit"
- #define GAME_OVER3_Y (BOX_BOT-10)
- #define GAME_OVER "*** GAME OVER ***"
- #define GAME_OVER_Y (BOX_BOT-40)
-
- #define CURRENT_WAVE " MINE WAVE %d "
- #define NEXT_WAVE1 "+*+ BONUS %05d +*+"
- #define NEXT_WAVE2 "*+* BONUS %05d *+*"
- #define NEXT_WAVE_Y (BOX_BOT-40)
-
- #define SCORE "SCORE %06ld"
- #define SCORE_X (BOX_LEF+24)
- #define SCORE_Y (BOX_TOP+40)
- #define LIVES "LIVES %d"
- #define LIVES_X (BOX_RIG-7*8-24)
- #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, score);
- }
-
- /**********************************************************************
- * Decrement lives
- **********************************************************************/
- void dec_lives(void)
- {
- if (lives>0)
- lives--;
-
- gr_dual_xy_printf(LIVES_X, LIVES_Y, LIVES, lives);
- }
-
- /**********************************************************************
- * Show the normal middle box on both pages. Leave 0 page active.
- **********************************************************************/
- void show_normal_box(void)
- {
- gr_setactivepage(1);
- setfillstyle(EMPTY_FILL, 0);
- bar(BOX_LEF+1, BOX_TOP+1, BOX_RIG-1, BOX_BOT-1);
- gr_setactivepage(0);
- setfillstyle(EMPTY_FILL, 0);
- bar(BOX_LEF+1, BOX_TOP+1, BOX_RIG-1, BOX_BOT-1);
-
- gr_dual_center_printf(STARMINES_Y, STARMINES);
- gr_dual_center_printf(COPYRIGHT_Y, COPYRIGHT);
- gr_dual_xy_printf(LIVES_X, LIVES_Y, LIVES, lives);
- gr_dual_xy_printf(SCORE_X, SCORE_Y, SCORE, score);
- gr_dual_center_printf(NEXT_WAVE_Y, CURRENT_WAVE, wave+1);
- }
-
- /**********************************************************************
- * Show the high scores on both pages. Leave 0 page active
- **********************************************************************/
- void show_hiscores(void)
- {
- SCORE_ENTRY *sep;
- int y;
-
- gr_setactivepage(1);
- setfillstyle(EMPTY_FILL, 0);
- bar(BOX_LEF+1, BOX_TOP+1, BOX_RIG-1, BOX_BOT-1);
- line(HISCORE_X,HISCORE_Y+9, HISCORE_X+strlen(HISCORE)*8,HISCORE_Y+9);
- gr_setactivepage(0);
- setfillstyle(EMPTY_FILL, 0);
- bar(BOX_LEF+1, BOX_TOP+1, BOX_RIG-1, BOX_BOT-1);
- line(HISCORE_X,HISCORE_Y+9, HISCORE_X+strlen(HISCORE)*8,HISCORE_Y+9);
-
- gr_dual_center_printf(HISCORE_Y, HISCORE);
- sep = smscores_get_first();
- y = HISCORES_Y;
- while (sep!=NULL) {
- gr_dual_center_printf(y, HISCORE3, sep->name, sep->score);
- y += 10;
- sep = smscores_get_next();
- }
- }
-
- /**********************************************************************
- * Ask for the name of the high scorer on current active page.
- **********************************************************************/
- void ask_name(SCORE_ENTRY *sep, int place)
- {
- show_hiscores();
- gr_xy_printf(HISCORE_X, HISCORE_Y, HISCORE2);
- gr_xy_printf(HISCORES_X, HISCORES_Y+10*place,
- HISCORE3, " ", sep->score);
- moveto(HISCORES_X, HISCORES_Y+10*place);
- gr_gets(sep->name, 18);
- }
-
- /**********************************************************************
- * 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;
- }
- else { /* inside the box */
- if (x>BOX_RIG-15) {
- lef = BOX_RIG; rig = gr_max_x; x = BOX_RIG+1;
- }
- else if (x <= (BOX_LEF+15)) {
- lef = 0; rig = BOX_LEF; x = BOX_LEF;
- }
- else if (y>BOX_BOT-15) {
- top = BOX_BOT; bot = gr_max_y; y = BOX_BOT;
- }
- else if (y <= (BOX_TOP+15)) {
- top = 0; bot = BOX_TOP; y = BOX_TOP;
- }
- else { /** This is a BUG **/
- setwritemode(1);
- rectangle(lef,top,rig,bot);
- rectangle(lef,top,rig,bot);
- gr_dual_xy_printf(0,0,"(%d,%d, %d,%d) ", x,y,asi->w,asi->h);
- }
- }
- 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)
- return SPR_ANIM_FX_RET_DESTROY;
- else
- if (asi->id>=EXPLO_ID)
- return SPR_ANIM_FX_RET_STOP;
- 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)
- return SPR_ANIM_FX_RET_DESTROY;
- else
- if (asi->id>=EXPLO_ID)
- return SPR_ANIM_FX_RET_STOP;
- 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;
-
- if (smspr_init_aliens(wave))
- exit(100); /** This should be impossible... **/
-
- for (i = 0; i < how_many; i++) {
- if ((alien=smspr_create_alien())==NULL)
- break;
- spr_anim_set_time(alien, 0, 5,
- alien_timeout + 20*i + (wave/HIT_DIVIDES_LIM)*50);
- 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++;
- }
- }
-
- /**********************************************************************
- * Initialize the wave'th alien attack.
- **********************************************************************/
- void wave_init(int wave)
- {
- alien_count = 0;
-
- /* 6,8,10,12, 4,5,6,7, 5,6,7,8, 9,10,..., 60 */
- if (wave/HIT_DIVIDES_LIM == 0)
- max_aliens = 6 + wave*2;
- else
- max_aliens = wave - (wave/HIT_DIVIDES_LIM > 1)*2;
- if (max_aliens>MAX_ALIEN)
- max_aliens = MAX_ALIEN;
-
- /* 300,310,320,330, 340,360,380,400, 300,320,340,360,..., 100 */
- if (wave/HIT_DIVIDES_LIM == 0)
- alien_timeout = 300 + 10*wave;
- else
- alien_timeout = 400 + 20*(wave%HIT_DIVIDES_LIM)
- - (wave/HIT_DIVIDES_LIM)*40;
- if (alien_timeout<100)
- alien_timeout = 100;
-
- /* 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,...*/
- alien_speed = 2 + (wave/HIT_DIVIDES_LIM);
-
- create_aliens(max_aliens);
-
- bonus = 2000 + wave*500;
- if (wave==0)
- score_inc = 5;
- else
- score_inc = 5*(wave*wave);
- }
-
- /**********************************************************************
- * Initialize player into the left side of the screen
- **********************************************************************/
- void player_init(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;
- }
-
- /**********************************************************************
- * Initializes the game. (Variables, background, aliens, player)
- * Return: Player sprite if all OK, NULL otherwise.
- **********************************************************************/
- ANIM_SPRITE game_init(void)
- {
- /** I want always the same alien sequence **/
- srand(42);
-
- /** global variables **/
- player_dead = player_immune = player_dying = 0;
- lives = 5;
- score = 0;
- score_inc = 5;
- bullets_flying = 0;
- wave = cheat_wave;
-
- /*** middle box ***/
- show_normal_box();
- gr_setactivepage(0);
- rectangle(BOX_LEF, BOX_TOP, BOX_RIG, BOX_BOT);
- gr_setactivepage(1);
- rectangle(BOX_LEF, BOX_TOP, BOX_RIG, BOX_BOT);
-
- /*** standard aliens ***/
- wave_init(wave);
-
- /*** the player if necessary ***/
- if (player==NULL)
- player = smspr_create_player();
- if (player==NULL)
- return NULL;
-
- player_init();
-
- return player;
- }
-
-
- /**********************************************************************
- * 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_stop(aliens[w].as);
- aliens[w].active = 0;
- 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:
- bullets_flying--;
- 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 or mark divide **/
- inc_score(score_inc);
- if (wave/HIT_DIVIDES_LIM && !aliens[w].divided)
- aliens[w].divide = aliens[w].shot = 1;
- else
- kill_alien(w);
- ret_code = SPR_ANIM_FX_RET_DESTROY;
- }
- break;
-
- default:
- sound(2000);delay(1000);nosound(); /** this is a bug **/
- }
- if (ret_code==SPR_ANIM_FX_RET_DESTROY)
- bullets_flying--;
- 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_STOP;
- 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_STOP && aspr==player_explosion) {
- player_explosion = NULL;
- player_dead = 1;
- }
- if (ret_code == SPR_ANIM_FX_RET_STOP)
- expls[asi->id - EXPLO_ID].active = 0;
-
- 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;
- int dir;
- ANIM_SPR_INFO *asi;
- ANIM_SPRITE as;
-
- if (gr_keys[GR_KEY_ESC])
- return 0;
-
- if (!player_dying) {
-
- /***** Rotations *****/
- dir = 0;
- if (gr_keys[GR_KEY_Z] || gr_keys[GR_KEY_ARROW_LEFT])
- dir += 1;
- if (gr_keys[GR_KEY_X] || gr_keys[GR_KEY_ARROW_RIGHT])
- dir += -1;
-
- if (dir) {
- asi = spr_anim_get_info(player);
- asi->frame = (asi->frame+dir)%16;
- spr_anim_set_time(player, asi->frame, -1,-1);
- }
-
- /***** Thrust *****/
- 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);
- }
-
- /***** Missiles *****/
- shot = 0;
- if (gr_keys[GR_KEY_SPACE]
- || gr_keys[GR_KEY_COMMA]
- || gr_keys[GR_KEY_DOT]) {
- shot = 1;
- if (bullet_count<6 && bullets_flying<MAX_BULLET) {
- bullet_count++;
- bullets_flying++;
- asi = spr_anim_get_info(player);
- as = smspr_create_bullet();
- if (as!=NULL) {
- asi->dx = player_dirs[asi->frame].dx*5;
- asi->dy = player_dirs[asi->frame].dy*5;
- asi->x = asi->x + missile_deltas[asi->frame].dx;
- asi->y = asi->y + missile_deltas[asi->frame].dy;
- 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)
- bullet_count--;
- }
-
- if (player_immune>0)
- player_immune--;
-
- 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);
- }
- }
-
- return (lives>0);
- }
-
-
- /**********************************************************************
- * Handle special events which have been initialized from fx routines:
- * - divide mines. timeout divides a mine always into four new mines.
- * - In waves 0..LIM, aliens divide only after timeout,
- * - In waves LIM..LIM-1, first shot divides initial mines into
- * two parts,
- * - In waves LIM*2..LIM*3-1 first shot divides initial mines into
- * three parts.
- * - In waves LIM*3..LIM*4-1 first shot divides initial mines into
- * four parts.
- * - In waves LIM*4... all mines are divided into 1-4 parts by
- * the first shot (this is hard!).
- * The initial properties of mines are changed by wave_init.
- * - start new wave after all mines killed.
- **********************************************************************/
- void handle_advancement(void)
- {
- ANIM_SPRITE as[4];
- ANIM_SPR_INFO *asi;
- int i,j;
-
- /** Divide the marked aliens **/
- for (i=0; i<MAX_ALIEN; i++) {
- if (aliens[i].divide) {
- aliens[i].divide = 0;
- if (aliens[i].active) {
- int div_count;
-
- if (aliens[i].shot)
- div_count = (1 + (wave/HIT_DIVIDES_LIM)%4);
- else
- div_count = 5;
- asi = spr_anim_get_info(aliens[i].as);
- spr_anim_stop(aliens[i].as);
- aliens[i].active = 0;
- aliens[i].shot = 0;
- alien_count--;
- for (i=0; i<4; i++) {
- if (i<div_count)
- as[i] = smspr_create_alien();
- else
- as[i] = NULL;
- if (as[i]!=NULL) {
- spr_anim_set_location(as[i], asi->x,asi->y);
- spr_anim_set_time(as[i], 0, 3, alien_timeout+10*i);
- set_limits(as[i], asi->x, asi->y);
- asi = spr_anim_get_info(as[i]);
- if (wave/HIT_DIVIDES_LIM < 4 || div_count < 5)
- aliens[asi->id].divided = 1;
- alien_count++;
- }
- }
- j = random(4);
- if (as[0]!=NULL)
- spr_anim_set_vector(as[0],
- mine_dir[j].dx*alien_speed, mine_dir[j].dy*alien_speed);
- j = (j+1)&3;
- if (as[1]!=NULL)
- spr_anim_set_vector(as[1],
- mine_dir[j].dx*alien_speed, mine_dir[j].dy*alien_speed);
- j = (j+1)&3;
- if (as[2]!=NULL)
- spr_anim_set_vector(as[2],
- mine_dir[j].dx*alien_speed, mine_dir[j].dy*alien_speed);
- j = (j+1)&3;
- if (as[3]!=NULL)
- spr_anim_set_vector(as[3],
- mine_dir[j].dx*alien_speed, mine_dir[j].dy*alien_speed);
- }
- }
- }
-
- /** start the next alien wave if all aliens killed **/
- if (alien_count<=0) {
- if (player_dying)
- dec_lives();
- if (lives>0) {
- for (i=1; i<30; i++) {
- gr_setactivepage(spr_anim_next_pass()^1);
- spr_regulate_speed();
- gr_center_printf(NEXT_WAVE_Y, NEXT_WAVE1, bonus);
- gr_setactivepage(spr_anim_next_pass()^1);
- spr_regulate_speed();
- gr_center_printf(NEXT_WAVE_Y, NEXT_WAVE2, bonus);
- }
- inc_score(bonus);
- wave++;
- gr_dual_center_printf(NEXT_WAVE_Y, CURRENT_WAVE, wave+1);
- wave_init(wave);
- player_init();
- }
- }
- if (bonus>0)
- bonus--;
- }
-
- /**********************************************************************
- * Animate f frames. Return also if Esc or space pressed.
- **********************************************************************/
- void animated_wait(int f)
- {
- int i;
-
- for (i=1; i<f && !gr_keys[GR_KEY_ESC] && !gr_keys[GR_KEY_SPACE]; i++) {
- gr_setactivepage(spr_anim_next_pass());
- spr_regulate_speed();
- }
- }
-
- /**********************************************************************
- * Show high scores and wait for a space or Esc.
- **********************************************************************/
- int idle(void)
- {
- int i;
-
- show_hiscores();
- gr_dual_center_printf(GAME_OVER2_Y, GAME_OVER2);
- gr_dual_center_printf(GAME_OVER3_Y, GAME_OVER3);
- do {
- gr_setactivepage(spr_anim_next_pass());
- spr_regulate_speed();
- delay(10);
-
- if (gr_keys[GR_KEY_C] && gr_keys[GR_KEY_H] && gr_keys[GR_KEY_E] &&
- gr_keys[GR_KEY_A] && gr_keys[GR_KEY_T] && !gr_keys[GR_KEY_R]) {
- cheat_wave++;
- sound(880); delay(250); nosound(); delay(250);
- }
-
- i = gr_inkey();
- } while (i!=27 && i!=' ');
-
- return i;
- }
-
- /**********************************************************************
- * Game over text. Wait for a keypress. Init new game or exit.
- * Return: 0 if user quitted.
- **********************************************************************/
- int game_over(void)
- {
- int i;
-
- gr_dual_center_printf(GAME_OVER_Y, GAME_OVER);
- animated_wait(40);
-
- if (player_dead) { /*** Only heroes make it to the Hall of Fame ***/
- i = smscores_check(score);
- if (i!=SCORE_COUNT) {
- gr_setactivepage(0);
- gr_setvisualpage(0);
- se.score = score;
- se.name[0] = '\0';
- smscores_add(&se);
- ask_name(&se, i);
- smscores_add(&se);
- }
- else
- animated_wait(80);
- }
-
- i = idle();
-
- if (i==27)
- return 0;
- else { /** kill surviving aliens and start a new game **/
- for (i=0; i<MAX_ALIEN; i++)
- if (aliens[i].active) {
- spr_anim_stop(aliens[i].as);
- aliens[i].active = 0;
- }
- game_init();
- }
- return 1;
- }
-
- /** farcore for saving background of MAX_ALIEN 2-frame aliens, **/
- /** 16 player shapes, 20 bullets and 20 4-frame explosions. **/
- #define MEM_NEEDED (80L*2*MAX_ALIEN*2 + \
- 96L*(sprite_resolution*2+2)*16 + \
- 8L*2*20 + \
- 120L*2*MAX_EXPL*4)
-
- /**********************************************************************
- * The main program
- **********************************************************************/
- void main(int argc, char **argv)
- {
- int i,j,x,y;
-
- puts("StarMines - a sprite toolkit demonstration game");
- puts(" Copyright (C) 1991 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!",
- 140 + MEM_NEEDED/1024L);
- exit(5);
- }
-
- gr_detect(GR_TYPE_SPR, &i, &j);
- if (i == -1) {
- puts("Unsupported graphics mode, sorry!");
- exit(10);
- }
- #ifdef BIND_DRIVERS
- {
- extern void HERCDRIVERPROC(void);
- extern void EGAVGADRIVERPROC(void);
-
- if (registerbgidriver(HERCDRIVERPROC)<0)
- puts(grapherrormsg(graphresult()));
- if (registerbgidriver(EGAVGADRIVERPROC)<0)
- puts(grapherrormsg(graphresult()));
- }
- #endif
-
- gr_text_mode = GR_MODE_CLEAR_FAST;
- gr_start(&i, &j);
- spr_initialize(i);
- cleardevice();
- smscores_init();
-
- srand(42); /** I want always the same stars **/
-
- /** Oh my god, it is full of stars... **/
- for (i=0; i<80; i++) {
- x=random(gr_max_x);
- y=random(gr_max_y);
- gr_setactivepage(0);
- putpixel(x, y, getmaxcolor());
- gr_setactivepage(1);
- putpixel(x, y, getmaxcolor());
- }
-
- if (game_init()==NULL) {
- gr_dual_xy_printf(0,0,"Initialization failed, press enter...");
- while(gr_inkey()==0)
- ;
- exit(20);
- }
-
- gr_start_kbd_grab();
- while (i) { /** the game main loop **/
- i = 1;
- while (i) { /** play until player dead or Esc pressed **/
- i = handle_player();
- gr_setactivepage(spr_anim_next_pass());
- spr_regulate_speed();
- handle_advancement();
- if (argc>2) /** watch out for those memory leaks **/
- gr_xy_printf(0,0,"%6lu %6lu",(long)coreleft(), farcoreleft());
- }
- i = game_over();
- }
- gr_end_kbd_grab();
- gr_end();
- exit(0);
- }
-