/* Space Rocks! Avoid the rocks as long as you can! {{{ Copyright (C) 2001 Paul Holt This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }}} */ #undef DEBUG #define EDITION " - The GREEBLIES edition" extern int font_height; void clearBuffer(); // includes {{{ #include #include #include #include #include #include #include #include #include #include #include "SFont.h" // }}} // constants {{{ #define XSIZE 640 #define YSIZE 480 #define NROCKS 6 // Number of rock image files, not number of rocks visible #define MAX_GREEBLE_IMAGES 100 // Max number of greeblie image files #define MAX_GREEBLES 100 // Max number of greeblies #define MAX_ROCKS 120 // MAX Rocks visible at once #define MAXROCKHEIGHT 100 //#define ROCKRATE 2 #define MAX_BLACK_POINTS 500 #define MAX_ENGINE_DOTS 5000 #define MAX_BANG_DOTS 500000 #define MAX_SPACE_DOTS 2000 #define W 100 #define M 255 //#define BIG_FONT_FILE "24P_Arial_NeonYellow.png" //#define BIG_FONT_FILE "20P_Babelfish.png" #define BIG_FONT_FILE "20P_Betadance.png" //#define SMALL_FONT_FILE "SmallNeon.png" // }}} // macros {{{ #define COND_ERROR(a) if ((a)) {initerror=strdup(SDL_GetError());return 1;} #define NULL_ERROR(a) COND_ERROR((a)==NULL) // }}} #define RANDOM_LIST_SIZE 32767 float random_list[RANDOM_LIST_SIZE]; int random_list_pointer; /* * Random numbers involve a call to the operating system, and may take some * time to complete. I can't call the random number generator multiple times * per frame. In one old version, it would take half a second before the ship * explosion was generated when the rnd() function was calling the operating * system function. * The solution is to generate random numbers during initialisation, and store * in a circular array. This will (of course) repeat, but it is not noticeable * (unless RANDOM_LIST_SIZE is very very small). */ void initrnd() {/*{{{*/ int i; for (i=0; i=RANDOM_LIST_SIZE) { random_list_pointer=0; } return random_list[random_list_pointer]; }/*}}}*/ /* * The input states are names for mappings between input device states and game * inputs. */ enum inputstates { UP, DOWN, LEFT, RIGHT, LASER, SHIELD, FAST, NOFAST, SCREENSHOT, _INPUTSTATESEND }; #define NUM_INPUTS (_INPUTSTATESEND+1) SDL_Joystick* joysticks[1]; #define JOYSTICK_DEADZONE 1024 // ************************************* STRUCTS struct rock_struct {/*{{{*/ // Array of black pixel coordinates around the rim of our ship. // This is scanned every frame to see if it's still black, and as // soon as it isn't we BLOW UP float x,y,xvel,yvel; int active; SDL_Surface *image; int type_number; float heat; // rock_struct.greeb is an index into greeb[], the destination (or landing // site) of the rock's greeb. This of course limits the number of greebs // flying to the same rock. int greeb; }; /*}}}*/ struct black_point_struct {/*{{{*/ int x,y; };/*}}}*/ struct bangdots {/*{{{*/ // Bang dots have the same colour as shield dots. // Bang dots get darker as they age. // Some are coloured the same as the ex-ship. float x,y,dx,dy; Uint16 c; // when zero, use heatcolor[bangdotlife] float life; // When reduced to 0, set active=0 int active; float decay;// Amount by which to reduce life each time dot is drawn };/*}}}*/ struct enginedots {/*{{{*/ // Engine dots stream out the back of the ship, getting darker as they go. int active; float x,y,dx,dy; // The life of an engine dot // is a number starting at between 0 and 50 and counting backward. float life; // When reduced to 0, set active=0 };/*}}}*/ struct spacedot {/*{{{*/ // Space dots are harmless background items // All are active. When one falls off the edge, another is created at the start. float x,y,dx; Uint16 color; };/*}}}*/ // High score table {{{ struct highscore { int score; char *name; int level; int allocated; } high[] = { {13000,"Pad",2,0}, {12500,"Pad",2,0}, {6500,"Pad",1,0}, {5000,"Pad",1,0}, {3000,"Pad",1,0}, {2500,"Pad",1,0}, {2000,"Pad",1,0}, {1500,"Pad",1,0} }; // }}} // ************************************* VARS int difficulty_level=1; float movementrate; // SDL_Surface global variables {{{ SDL_Surface *surf_screen, // Screen *surf_t_rock, // Title element "rock" *surf_t_dodgers, // Title element "dodgers" *surf_t_gameover, // Title element "gameover" *surf_t_game, // Title element "game" *surf_t_over, // Title element "over" *surf_t_paused, // Title element "paused" *surf_ship, // Spaceship element *surf_small_ship, // Indicator of number of ships remaining *surf_rock[NROCKS], // THE ROCKS *surf_greeblies[MAX_GREEBLE_IMAGES], // THE GREEBLIES *surf_deadrock[NROCKS], // THE DEAD ROCKS (blank white rocks) *surf_font_big, // The big font *surf_font_small, // The small font *surf_gauge, // The raw gauge image *surf_gauge_shield[2], // The shield gauge 0=on,1=off *surf_gauge_laser[2]; // The laser gauge 0=on,1=off // }}} // Structure global variables {{{ struct enginedots edot[MAX_ENGINE_DOTS], *dotptr=edot; struct rock_struct rock[MAX_ROCKS], *rockptr=rock; struct black_point_struct black_point[MAX_BLACK_POINTS], *blackptr=black_point; struct bangdots bdot[MAX_BANG_DOTS], *bdotptr=bdot; struct spacedot sdot[MAX_SPACE_DOTS]; struct greeble { int active; float x,y; // When landed, these represent an offset from the host rock int target_rock_number; // no longer used. use rock_struct.greeb int landed; int boredom; // Goes up while landed }; struct greeble greeb[MAX_GREEBLES]; // }}} void init_greeblies() { int i; for (i=0; i3*XSIZE) { // Create a new greeb, alive, flying, from the right side of the screen at a // random position. g->active = 1; g->landed = 0; g->x = XSIZE; g->y = rnd()*YSIZE; // It's flying to this rock, and the rock knows it. g->target_rock_number = i; rock[i].greeb = g-greeb; return; } } } void activate_one_greeblie() { // (maybe ... if possible) int i; for (i=0; iactive) { //rock[g->target_rock_number].greeb = i; if (g->landed) { g->boredom++; // Landed greebles may take it into thier head to jump off their // rock and travel to a new one. if (rnd()<(0.001*(g->boredom-100))) { int j; for (j=0; j<(MAX_ROCKS/10) && g->landed; j++) { // Find a target int i=rnd()*MAX_ROCKS; int dx; struct rock_struct *r = &rock[i]; if (r->active && r->greeb==0 && (dx=(rock[g->target_rock_number].x-r->x))>0 && dxx += rock[g->target_rock_number].x; g->y += rock[g->target_rock_number].y; rock[g->target_rock_number].greeb = 0; g->target_rock_number = i; r->greeb = g-greeb; g->active = 1; g->landed = 0; } } // It's no problem if we don't find a target, just don't // bother leaving the current one. } // If the greeble leaves the left side of the screen, he's gone. if (rock[g->target_rock_number].x + g->x<0) { g->active=0; rock[g->target_rock_number].greeb = 0; } } else { float dx = g->x - rock[g->target_rock_number].x+10; float dy = g->y - rock[g->target_rock_number].y+10; float dist = sqrt(dx*dx+dy*dy); // Greebles are attracted to rocks. If the greeble is within a // certain distance of the target rock, set it to 'landed' mode. if ( dist < 10) { g->landed=1; g->boredom=0; // Change the greeble coordinates to represent the // offset from the host rock. g->x = dx-10; g->y = dy-10; } else { g->x -= 20*movementrate*dx/dist; g->y -= 10*movementrate*dy/dist; } } } } } void display_greeb(struct greeble *g) { static SDL_Rect src,dest; if (g->active) { if (g->landed) { dest.x = (int)(g->x+rock[g->target_rock_number].x); dest.y = (int)(g->y+rock[g->target_rock_number].y); } else { dest.x = (int)(g->x); dest.y = (int)(g->y); } src.x = 0; src.y = 0; src.w = surf_greeblies[0]->w; src.h = surf_greeblies[0]->h; dest.w = src.w; dest.h = src.h; SDL_BlitSurface(surf_greeblies[0],&src,surf_screen,&dest); } } // Other global variables {{{ char topline[1024]; char *initerror = ""; char name[1024], debug1[1024]; float xship,yship; // X position, 0..XSIZE float xvel,yvel; // Change in X position per tick. float rockrate,rockspeed; float shieldlevel, laserlevel, shieldpulse=0; int nships,score,initticks,ticks_since_last, last_ticks; int initialshield, gameover, fast; float countdown=0; float level=0; int maneuver = 0; int laser = 0; int shieldsup=0; int oss_sound_flag=0; int scorerank; float fadetimer=0,faderate; int joystick_flag = 1; int pausedown=0,paused=0; // bangdot start (bd1) and end (bd2) position: int bd1=0, bd2=0; int xoffset[NROCKS][MAXROCKHEIGHT]; enum states {/*{{{*/ TITLE_PAGE, GAME_PLAY, DEAD_PAUSE, GAME_OVER, HIGH_SCORE_ENTRY, HIGH_SCORE_DISPLAY, DEMO };/*}}}*/ enum states state=TITLE_PAGE; float state_timeout = 600.0; char *sequence[] = { "Press SPACE to start", "http://spacerocks.sourceforge.net", "Email patches to pad@pcholt.com", "Chat on #SDL at irc.openprojects.net", "G'day tesmako, overcode, Briareos", "Arrow keys move the ship, S=shield and D=laser.", "You can bounce off the sides of the screen.", "", "If you have a slow machine, tell me how this game performs!", "", "The little green guys are called Greeblies", "The graphics for the Greeblies are not finished yet. Contributions welcome.", "", "More features planned, including powerups, heat-seekers...", "...and shockwave generators. Stay tuned!", "", }; int bangdotlife, nbangdots; Uint16 heatcolor[W*3]; char *data_dir; extern char *optarg; extern int optind, opterr, optopt; // }}} // ************************************* FUNCS #ifdef DOTCOLLISION int dotcollision(SDL_Surface *s) {/*{{{*/ int i,j,m; Uint16 *rawpixel, *r; /* * Kill all the dots which collide with other objects. * This does not work, it's probably in the wrong place or something. */ SDL_LockSurface(s); rawpixel = (Uint16 *) s->pixels; if (bangdotlife > 0 && bangdotlife<80) { for (i=0; i0 && bdot[i].x0 && bdot[i].ypitch/2*(int)(bdot[i].y))+(int)(bdot[i].x)]; if (*r != (bdot[i].c ? bdot[i].c : heatcolor[bangdotlife*2])) bdot[i].active=0; } } } SDL_UnlockSurface(s); return; }/*}}}*/ #endif FILE *hs_fopen(char *mode) {/*{{{*/ FILE *f; mode_t mask; mask = umask(0111); if (f=fopen("/var/games/rockdodger.highscore",mode)) { umask(mask); return f; } else { char s[1024]; umask(0177); snprintf(s,1024,"%s/.rockdodger_high",getenv("HOME")); if (f=fopen(s,mode)) { umask(mask); return f; } else { umask(mask); return 0; } } }/*}}}*/ void read_high_score_table() {/*{{{*/ FILE *f; int i; if (f=hs_fopen("r")) { // If the file exists, read from it for (i=0; i<8; i++) { char s[1024]; int highscore; if (fscanf (f, "%d %1023[^\n]", &highscore, s)!=2) break; if (high[i].allocated) free(high[i].name); high[i].name = strdup(s); high[i].score = highscore; high[i].allocated = 1; } fclose(f); } }/*}}}*/ void write_high_score_table() {/*{{{*/ FILE *f; int i; if (f=hs_fopen("w")) { // If the file exists, write to it for (i=0; i<8; i++) { fprintf (f, "%d %s\n", high[i].score, high[i].name); } fclose(f); } }/*}}}*/ void init_engine_dots() {/*{{{*/ int i; for (i=0; iformat,intensity,intensity,intensity); } }/*}}}*/ inc_score(int x, int y, int dscore) { score += dscore; } kill_greeb(int hitgreeb) { struct greeble *g; int r; g = &greeb[hitgreeb]; g->active = 0; if (r=g->target_rock_number) rock[r].greeb = 0; if (g->landed) { play_sound(1+(int)(rnd()*3)); makebangdots( (int)(g->x + rock[g->target_rock_number].x), (int)(g->y + rock[g->target_rock_number].y), 0, 0, surf_greeblies[0], 15, 1 ); /* */ } else { makebangdots( (int)(g->x), (int)(g->y), 0, 0, surf_greeblies[0], 15, 1); play_sound(1+(int)(rnd()*3)); } inc_score(g->x,g->y,2500); } void drawlaser() {/*{{{*/ int i,xc,hitrock,hitgreeb; Uint16 c, *rawpixel; if (laserlevel<0) return; laserlevel-=movementrate; if (laserlevel<0) { // If the laser runs out completely, there will be a delay before it can be brought back up laserlevel=-W/2; return; } hitrock = -1; hitgreeb = -1; xc = XSIZE; // let xc = x coordinate of the collision between the laser and a space rock // 1. Calculate xc and determine the asteroid that was hit for (i=0; irock[i].y && yship+12h && xship+32w/2) && rock[i].x+(rock[i].image->w/2) < xc) { xc = rock[i].x+(rock[i].image->w/2); hitrock = i; } } } for (i=0; iactive) { int greebx = (int)g->x; int greeby = (int)g->y; if (g->landed) { greebx += rock[g->target_rock_number].x; greeby += rock[g->target_rock_number].y; } if (yship+12>greeby && yship+12=0) { rock[hitrock].heat += movementrate*3; } if (hitgreeb>=0) kill_greeb(hitgreeb); // Plot a number of random dots between xship and XSIZE SDL_LockSurface(surf_screen); rawpixel = (Uint16 *) surf_screen->pixels; c = SDL_MapRGB(surf_ship->format,rnd()*128,128+rnd()*120,rnd()*128); for (i=0; i<(xc-xship)*5; i+=10) { int x,y; x = rnd()*(xc-(xship+32))+xship+32; y = yship+12+(rnd()-0.5)*1.5; rawpixel[surf_screen->pitch/2*y+x]=c; } SDL_UnlockSurface(surf_screen); }/*}}}*/ int makebangdots(int xbang, int ybang, int xvel, int yvel, SDL_Surface *s, int power, int amtdots) {/*{{{*/ // TODO - stop generating dots after a certain amount of time has passed, to cope with slower CPUs. int i,x,y,n,endcount; Uint16 *rawpixel,c; double theta,r,dx,dy; int begin_generate; begin_generate = SDL_GetTicks(); SDL_LockSurface(s); rawpixel = (Uint16 *) s->pixels; //for (n=0; n<=power/2; n++) { endcount = 0; while (endcountw; x++) { for (y=0; yh; y++) { c = rawpixel[s->pitch/2*y+x]; if (c && c != SDL_MapRGB(s->format,0,255,0)) { theta = rnd()*M_PI*2; r = 1-(rnd()*rnd()); bdot[bd2].dx = (power/50.0)*45.0*cos(theta)*r+xvel; bdot[bd2].dy = (power/50.0)*45.0*sin(theta)*r+yvel; bdot[bd2].x = x+xbang; bdot[bd2].y = y+ybang; // Replace the last few bang dots with the pixels from the exploding object bdot[bd2].c = (endcount>0)?c:0; bdot[bd2].life = 100; bdot[bd2].decay = rnd()*3+1; bdot[bd2].active = 1; bd2++; if (bd2>=MAX_BANG_DOTS) bd2=0; // If the circular buffer is filled, who cares? They've had their chance. //if (bd2==bd1-1) goto exitloop; } } } if (SDL_GetTicks() - begin_generate > 3) endcount++; } exitloop: SDL_UnlockSurface(s); }/*}}}*/ void draw_bang_dots(SDL_Surface *s) {/*{{{*/ int i; int first_i, last_i; Uint16 *rawpixel; rawpixel = (Uint16 *) s->pixels; first_i = -1; for (i=bd1; (bd1<=bd2)?(i=bd1 && i=XSIZE || bdot[i].y<=0 || bdot[i].y>=YSIZE) { // If the dot has drifted outside the perimeter, kill it bdot[i].active = 0; } if (bdot[i].active) { //printf("%d %d\n",bd1,bd2); if (first_i < 0) first_i = i; //last_i = i+1; rawpixel[(int)(s->pitch/2*(int)(bdot[i].y))+(int)(bdot[i].x)] = bdot[i].c ? bdot[i].c : heatcolor[(int)(bdot[i].life*3)]; bdot[i].life-=bdot[i].decay * movementrate; bdot[i].x += bdot[i].dx*movementrate; bdot[i].y += bdot[i].dy*movementrate; if (bdot[i].life<0) bdot[i].active = 0; } //printf("/n"); //exit(0); } if (first_i>=0) { bd1 = first_i; bd2 = last_i; //printf("new %d %d\n",bd1,bd2); //fprintf (stderr,"%d - %d\n", bd1,bd2); } else { bd1 = 0; bd2 = 0; //fprintf (stderr,"reset\n"); } }/*}}}*/ void draw_space_dots(SDL_Surface *s) {/*{{{*/ int i; Uint16 *rawpixel; rawpixel = (Uint16 *) s->pixels; for (i=0; ipitch/2*(int)sdot[i].y)+(int)(sdot[i].x)] = sdot[i].color; sdot[i].x += sdot[i].dx*movementrate; if (sdot[i].x<0) sdot[i].x=XSIZE; } }/*}}}*/ void draw_engine_dots(SDL_Surface *s) {/*{{{*/ int i; Uint16 *rawpixel; rawpixel = (Uint16 *) s->pixels; for (i=0; iYSIZE) edot[i].active=0; else if (edot[i].x<0 || edot[i].x>XSIZE) { edot[i].active=0; } else { int heatindex; heatindex = edot[i].life * 6; //rawpixel[(int)(s->pitch/2*(int)(edot[i].y))+(int)(edot[i].x)] = lifecolor[(int)(edot[i].life)]; rawpixel[(int)(s->pitch/2*(int)(edot[i].y))+(int)(edot[i].x)] = heatindex>3*W ? heatcolor[3*W-1] : heatcolor[heatindex]; } } } }/*}}}*/ void create_engine_dots(int newdots) { int i; double theta,r,dx,dy; if (state==GAME_PLAY) for (i=0; iactive==0) { theta = rnd()*M_PI*2; r = rnd(); dx = cos(theta)*r; dy = sin(theta)*r; dotptr->active=1; dotptr->x=xship+surf_ship->w/2-14; dotptr->y=yship+surf_ship->h/2+(rnd()-0.5)*5-1; dotptr->dx=10*(dx-1.5)+xvel; dotptr->dy=1*dy+yvel; dotptr->life=45+rnd(1)*5; dotptr++; if (dotptr-edot>=MAX_ENGINE_DOTS) dotptr = edot; } } } void create_engine_dots2(int newdots, int m) { int i; double theta,r,dx,dy; // Don't create fresh engine dots when // the game is not being played and a demo is not beng shown if (state!=GAME_PLAY && state!=DEMO) return; for (i=0; iactive==0) { theta = rnd()*M_PI*2; r = rnd(); dx = cos(theta)*r; dy = sin(theta)*r; dotptr->active=1; dotptr->x=xship+surf_ship->w/2+(rnd()-0.5)*1; dotptr->y=yship+surf_ship->h/2+(rnd()-0.5)*1; switch(m) { case 0: dotptr->x-=14; dotptr->dx=5*(dx-1.5)+xvel; dotptr->dy=1*dy+yvel; break; case 1: dotptr->dy=5*(dy-1.5)+yvel; dotptr->dx=1*dx+xvel; break; case 2: dotptr->x+=14; dotptr->dx=-5*(dx-1.5)+xvel; dotptr->dy=1*dy+yvel; break; case 3: dotptr->dy=5*(dy+1.5)+yvel; dotptr->dx=1*dx+xvel; break; } dotptr->life=45+rnd(1)*20; dotptr++; if (dotptr-edot>=MAX_ENGINE_DOTS) dotptr = edot; } } } int drawdots(SDL_Surface *s) {/*{{{*/ int m; SDL_LockSurface(s); // Draw the background stars (aka space dots - they can't possibly be stars // because then we'd be moving past them at something like 10,000 times the // speed of light) draw_space_dots(s); // Draw all the engine dots draw_engine_dots(s); // Create more engine dots comin out da back if (!gameover) create_engine_dots(100); // Create engine dots out the side we're moving from for (m=0; m<4; m++) if (maneuver & 1< 0) draw_bang_dots(s); SDL_UnlockSurface(s); }/*}}}*/ char * load_file(char *s) {/*{{{*/ static char retval[1024]; snprintf(retval, 1024, "%s/%s", data_dir, s); return retval; } /*}}}*/ int missing(char *dirname) {/*{{{*/ struct stat buf; stat(dirname, &buf); return (!S_ISDIR(buf.st_mode)); }/*}}}*/ int num_greeblies = 0; int init(int fullscreen) {/*{{{*/ int i,j; SDL_Surface *temp; Uint16 *raw_pixels; Uint32 flag; read_high_score_table(); // Where is the images datafile? // default: ./images // second alternative: ROCK_DODGERS_IMAGEDIR // final alternative: /usr/local/share/rockdodger/images data_dir = strdup("./data"); if (missing(data_dir)) { char *env; env = getenv("ROCK_DODGERS_IMAGEDIR"); if (env != NULL) { data_dir = strdup(getenv("ROCK_DODGERS_IMAGEDIR")); if (missing(data_dir)) { fprintf (stderr,"Cannot find data directory $ROCK_DODGERS_IMAGEDIR\n"); exit(-1); } } else { data_dir = strdup("/usr/local/share/rockdodger/data"); if (missing(data_dir)) { fprintf (stderr,"Cannot find data in %s\n", data_dir); exit(-2); } } } if (oss_sound_flag) { // Initialise SDL with audio and video if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)!=0) { oss_sound_flag=0; printf ("Can't open sound, starting without it\n"); atexit(SDL_Quit); } else { atexit(SDL_Quit); atexit(SDL_CloseAudio); oss_sound_flag = init_sound(); } } else { // Initialise with video only COND_ERROR(SDL_Init(SDL_INIT_VIDEO)!=0); atexit(SDL_Quit); } // Attempt to initialize a joystick if (joystick_flag) { if (SDL_InitSubSystem (SDL_INIT_JOYSTICK) != 0) { joystick_flag = 0; printf ("Can't initialize joystick subsystem, starting without it.\n"); } else { int njoys; njoys = SDL_NumJoysticks (); printf ("%d joystick(s) detected\n", njoys); if (njoys == 0) { printf ("That's not enough joysticks to start with joystick support\n"); joystick_flag = 0; } else { joysticks[0] = SDL_JoystickOpen (0); if (joysticks[0] == NULL) { printf ("Couldn't open joystick %d\n", 0); joystick_flag = 0; } } } } if (oss_sound_flag) play_tune(0); // Attempt to get the required video size flag = SDL_DOUBLEBUF | SDL_HWSURFACE; if (fullscreen) flag |= SDL_FULLSCREEN; surf_screen = SDL_SetVideoMode(XSIZE,YSIZE,16,flag); // Set the title bar text SDL_WM_SetCaption("Rock Dodgers", "rockdodgers"); NULL_ERROR(surf_screen); // Set the heat color from the range 0 (cold) to 300 (blue-white) for (i=0; iformat, (iformat,255,0,0)); NULL_ERROR(surf_t_rock = SDL_DisplayFormat(temp)); NULL_ERROR(temp = IMG_Load(load_file("dodgers.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,255,0,0)); NULL_ERROR(surf_t_dodgers = SDL_DisplayFormat(temp)); NULL_ERROR(temp = IMG_Load(load_file("game.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,255,0,0)); NULL_ERROR(surf_t_game = SDL_DisplayFormat(temp)); NULL_ERROR(temp = IMG_Load(load_file("gauge.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,0,0)); NULL_ERROR(surf_gauge = SDL_DisplayFormat(temp)); /* NULL_ERROR(temp = IMG_Load(load_file("laser0.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,0,0)); NULL_ERROR(surf_gauge_laser[0] = SDL_DisplayFormat(temp)); NULL_ERROR(temp = IMG_Load(load_file("laser1.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,0,0)); NULL_ERROR(surf_gauge_laser[1] = SDL_DisplayFormat(temp)); */ NULL_ERROR(surf_gauge_laser[0] = IMG_Load(load_file("laser0.png"))); NULL_ERROR(surf_gauge_laser[1] = IMG_Load(load_file("laser1.png"))); NULL_ERROR(surf_gauge_shield[0] = IMG_Load(load_file("shield0.png"))); NULL_ERROR(surf_gauge_shield[1] = IMG_Load(load_file("shield1.png"))); NULL_ERROR(surf_t_gameover = IMG_Load(load_file("gameover2.png"))); /* NULL_ERROR(temp = IMG_Load(load_file("shield0.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,0,0)); NULL_ERROR(surf_gauge_shield[0] = SDL_DisplayFormat(temp)); NULL_ERROR(temp = IMG_Load(load_file("shield1.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,0,0)); NULL_ERROR(surf_gauge_shield[1] = SDL_DisplayFormat(temp)); */ NULL_ERROR(temp = IMG_Load(load_file("over.png"))); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,255,0,0)); NULL_ERROR(surf_t_over = SDL_DisplayFormat(temp)); NULL_ERROR(surf_t_gameover = IMG_Load(load_file("gameover2.png"))); NULL_ERROR(surf_t_paused = IMG_Load(load_file("paused.png"))); surf_font_big = IMG_Load(load_file(BIG_FONT_FILE)); InitFont(surf_font_big); //surf_font_small = IMG_Load(load_file(SMALL_FONT_FILE)); // InitFont(surf_font_small); // Load the spaceship surface from the spaceship file temp = SDL_LoadBMP(load_file("ship.bmp")); NULL_ERROR(temp); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,255,0)); surf_ship = SDL_DisplayFormat(temp); NULL_ERROR(surf_ship); // Load the little spaceship surface from the spaceship file temp = SDL_LoadBMP(load_file("ship_small.bmp")); NULL_ERROR(temp); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,255,0)); surf_small_ship = SDL_DisplayFormat(temp); NULL_ERROR(surf_small_ship); // Create the array of black points; SDL_LockSurface(surf_ship); raw_pixels = (Uint16 *) surf_ship->pixels; for (i=0; iw; i++) for (j=0; jh; j++) if (raw_pixels[j*(surf_ship->pitch)/2+i] == 0) { blackptr->x = i; blackptr->y = j; blackptr++; } SDL_UnlockSurface(surf_ship); init_engine_dots(); init_space_dots(); init_greeblies(); // Load all our lovely rocks for (i=0; iformat,0,255,0)); surf_rock[i] = SDL_DisplayFormat(temp); NULL_ERROR(surf_rock[i]); sprintf(a,load_file("deadrock%d.bmp"),i); temp = SDL_LoadBMP(a); NULL_ERROR(temp); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,255,0)); surf_deadrock[i] = SDL_DisplayFormat(temp); NULL_ERROR(surf_deadrock[i]); } // Load all the available greeblies for (i=0; ;i++) { char a[100]; sprintf(a,load_file("greeblie%d.bmp"),i); temp = SDL_LoadBMP(a); if (!temp) { num_greeblies = i; break; } NULL_ERROR(temp); SDL_SetColorKey(temp,SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint16) SDL_MapRGB(temp->format,0,0,255)); surf_greeblies[i] = SDL_DisplayFormat(temp); NULL_ERROR(surf_greeblies[i]); } printf ("%d greeblies found\n",num_greeblies); // Remove the mouse cursor #ifdef SDL_DISABLE SDL_ShowCursor(SDL_DISABLE); #endif return 0; }/*}}}*/ void showgauge(int x, SDL_Surface *surf[2], float fraction) { static int endx,w; static SDL_Rect src,dest; src.y=0; if (fraction>0) { if (fraction>1) fraction=1.0; src.x=0; w = src.w = surf[0]->w * fraction; src.h = surf[0]->h; endx = src.w; dest.w = src.w; dest.h = src.h; dest.x = x; dest.y = YSIZE-src.h-10; SDL_BlitSurface(surf[0],&src,surf_screen,&dest); } else { endx = 0; w = 0; } src.x = endx; src.w = surf[1]->w - w; src.h = surf[1]->h; dest.w = src.w; dest.h = src.h; dest.x = x+endx; dest.y = YSIZE-src.h-10; SDL_BlitSurface(surf[1],&src,surf_screen,&dest); } int draw() {/*{{{*/ int i,n; SDL_Rect src,dest; struct black_point_struct *p; Uint16 *raw_pixels; int bang, offset, x; char *text; float fadegame,fadeover; int nsequence; char *statedisplay, buf[1024]; static last_rock=1; nsequence = sizeof(sequence)/sizeof(char *); bang=0; src.x=0; src.y=0; dest.x=0; dest.y=0; // Draw a fully black background { Uint32 c; float t; float l = level-(int)level; if (l>0.98) { t = 4*(1-(1-l)/(1-0.98)); play_sound(4); switch((int)t) { case 0: c = SDL_MapRGB(surf_screen->format,(int)(255*t),0,0); break; case 1: c = SDL_MapRGB(surf_screen->format,(int)(255*(1-t)),(int)(255*(t-1)),0); break; case 2: c = SDL_MapRGB(surf_screen->format,0,(int)(255*(3-t)),(int)(255*(t-3))); break; case 3: c = SDL_MapRGB(surf_screen->format,0,0,(int)(255*(4-t))); break; } } else { c = 0; } SDL_FillRect(surf_screen, NULL, c); } #ifdef DEBUG // DEBUG {{{ // Show the current state switch (state) { case TITLE_PAGE: statedisplay = "title_page"; break; case GAME_PLAY: statedisplay = "gameplay"; break; case DEAD_PAUSE: statedisplay = "dead_pause"; break; case GAME_OVER: statedisplay = "game_over"; break; case HIGH_SCORE_ENTRY: statedisplay = "high_score_entry"; break; case HIGH_SCORE_DISPLAY: statedisplay = "high_score_display"; break; case DEMO: statedisplay = "demo"; break; } snprintf(buf,1024, "mode=%s", statedisplay); PutString(surf_screen,0,YSIZE-50,buf); // }}} #endif // Draw the background dots drawdots(surf_screen); // If it's firing, draw the laser if (laser) { drawlaser(); } else { if (laserlevel<3*W) { laserlevel += movementrate/4; } } // Draw ship if (!gameover && (state==GAME_PLAY || state==DEMO) ) { src.w = surf_ship->w; src.h = surf_ship->h; dest.w = src.w; dest.h = src.h; dest.x = (int)xship; dest.y = (int)yship; SDL_BlitSurface(surf_ship,&src,surf_screen,&dest); } // Before the rocks are drawn, the greeblies are shown playing amongst them. if (rnd()<.002*level || state==TITLE_PAGE) activate_one_greeblie(); move_all_greeblies(); for (i=0; iactive) { if (!r->greeb) last_rock = i; src.w = r->image->w; src.h = r->image->h; dest.w = src.w; dest.h = src.h; dest.x = (int) r->x; dest.y = (int) r->y; // Draw the rock SDL_BlitSurface(r->image,&src,surf_screen,&dest); // Draw the heated part of the rock, in an alpha which reflects the // amount of heat in the rock. if (r->heat>0) { SDL_Surface *deadrock; deadrock = surf_deadrock[r->type_number]; SDL_SetAlpha(deadrock,SDL_SRCALPHA,r->heat*255/r->image->h); dest.x = (int) r->x; // kludge SDL_BlitSurface(deadrock,&src,surf_screen,&dest); if (rnd()<0.3) r->heat-=movementrate; } // If the rock is heated past a certain point, the water content of // the rock flashes to steam, releasing enough energy to destroy // the rock in spectacular fashion. if (rock[i].heat>rock[i].image->h) { int g; rock[i].active=0; play_sound(1+(int)(rnd()*3)); makebangdots(rock[i].x,rock[i].y,rock[i].xvel,rock[i].yvel,rock[i].image,10,3); // If a greeblie was going to this rock if (g=rock[i].greeb) { // ...and had landed, then the greeblie explodes too. if (greeb[g].landed) kill_greeb(g); else { // If the greeblie is not yet landed, then it must now // find another rock to jump to. Choose the last active // rock found. rock[i].greeb=0; rock[last_rock].greeb=g; greeb[g].target_rock_number = last_rock; } } } } // Draw any greeblies attached to (or going to) the rock, whether the rock is active or not. if (r->greeb && greeb[r->greeb].target_rock_number==i) display_greeb(&greeb[r->greeb]); } // Remove this when necessary //display_greeblies(); // If it's game over, show the game over graphic in the dead centre switch (state) { case GAME_OVER: if (fadetimer<3.0/faderate) fadegame=fadetimer/(3.0/faderate); else fadegame=1.0; if (fadetimer<3.0/faderate) fadeover=0.0; else if (fadetimer<6.0/faderate) fadeover = ((3.0/faderate)-fadetimer)/(6.0/faderate); else fadeover = 1.0; src.w = surf_t_game->w; src.h = surf_t_game->h; dest.w = src.w; dest.h = src.h; dest.x = (XSIZE-src.w)/2; dest.y = (YSIZE-src.h)/2-40; //SDL_SetAlpha(surf_t_gameover, SDL_SRCALPHA, 0); //SDL_BlitSurface(surf_t_gameover,&src,surf_screen,&dest); SDL_SetAlpha(surf_t_game, SDL_SRCALPHA, (int)(fadegame*(200+55*cos(fadetimer+=movementrate/1.0)))); SDL_BlitSurface(surf_t_game,&src,surf_screen,&dest); src.w = surf_t_over->w; src.h = surf_t_over->h; dest.w = src.w; dest.h = src.h; dest.x = (XSIZE-src.w)/2; dest.y = (YSIZE-src.h)/2+40; SDL_SetAlpha(surf_t_over, SDL_SRCALPHA, (int)(fadeover*(200+55*sin(fadetimer)))); SDL_BlitSurface(surf_t_over,&src,surf_screen,&dest); break; case TITLE_PAGE: src.w = surf_t_rock->w; src.h = surf_t_rock->h; dest.w = src.w; dest.h = src.h; dest.x = (XSIZE-src.w)/2 + cos(fadetimer/6.5)*10; dest.y = (YSIZE/2-src.h)/2 + sin(fadetimer/5)*10; SDL_SetAlpha(surf_t_rock, SDL_SRCALPHA, (int)(200+55*sin(fadetimer+=movementrate/2.0))); SDL_BlitSurface(surf_t_rock,&src,surf_screen,&dest); src.w = surf_t_dodgers->w; src.h = surf_t_dodgers->h; dest.w = src.w; dest.h = src.h; dest.x = (XSIZE-src.w)/2+sin(fadetimer/6.5)*10; dest.y = (YSIZE/2-src.h)/2 + surf_t_rock->h + 20 + sin((fadetimer+1)/5)*10; SDL_SetAlpha(surf_t_dodgers, SDL_SRCALPHA, (int)(200+55*sin(fadetimer-1.0))); SDL_BlitSurface(surf_t_dodgers,&src,surf_screen,&dest); text = "Version " VERSION EDITION " (" COMPILEDATE ")"; x = (XSIZE-SFont_wide(text))/2 + sin(fadetimer/4.5)*10; PutString(surf_screen,x,YSIZE-50+sin(fadetimer/2)*5,text); text = sequence[(int)(fadetimer/40)%nsequence]; x = (XSIZE-SFont_wide(text))/2 + cos(fadetimer/4.5)*10; PutString(surf_screen,x,YSIZE-100+cos(fadetimer/3)*5,text); break; case HIGH_SCORE_ENTRY: if (score >= high[7].score) { play_tune(2); if (SFont_Input (surf_screen, 330, 50+(scorerank+2)*font_height, 300, name)) { // Insert name into high score table // Lose the lowest name forever (loser!) //if (high[7].allocated) // free(high[7].name); // THIS WAS CRASHING SO I REMOVED IT // Insert new high score high[scorerank].score = score; high[scorerank].name = strdup(name); // MEMORY NEVER FREED! high[scorerank].allocated = 1; // Set the global name string to "", ready for the next winner name[0]=0; // Change state to briefly show high scores page state = HIGH_SCORE_DISPLAY; state_timeout=200; // Write the high score table to the file write_high_score_table(); // Play the title page tune play_tune(0); } } else { state = HIGH_SCORE_DISPLAY; state_timeout=400; } case HIGH_SCORE_DISPLAY: // Display de list o high scores mon. PutString(surf_screen,180,50,"High scores"); for (i=0; i<8; i++) { char s[1024]; sprintf(s, "#%1d",i+1); PutString(surf_screen, 150, 50+(i+2)*font_height,s); sprintf(s, "%04d", high[i].score); PutString(surf_screen, 200, 50+(i+2)*font_height,s); sprintf(s, "%3s", high[i].name); PutString(surf_screen, 330, 50+(i+2)*font_height,s); } fadetimer+=movementrate/2.0; text = "Version " VERSION EDITION " (" COMPILEDATE ")"; x = (XSIZE-SFont_wide(text))/2 + sin(fadetimer/4.5)*10; PutString(surf_screen,x,YSIZE-50+sin(fadetimer/2)*5,text); text = sequence[(int)(fadetimer/40)%nsequence]; x = (XSIZE-SFont_wide(text))/2 + cos(fadetimer/4.5)*10; PutString(surf_screen,x,YSIZE-100+cos(fadetimer/3)*5,text); } if (!gameover && state==GAME_PLAY) { // Show the freaky shields SDL_LockSurface(surf_screen); raw_pixels = (Uint16 *) surf_screen->pixels; if (initialshield>0 || shieldsup && shieldlevel>0) { int x,y,l; Uint16 c; if (initialshield>0) { initialshield-=movementrate; c = SDL_MapRGB(surf_screen->format,0,255,255); } else { c = heatcolor[(int)shieldlevel]; shieldlevel-=movementrate; } shieldpulse += 0.1; for (p=black_point; px + (int)xship + (rnd()+rnd()-1)*sin(shieldpulse)*4 + 1; y = p->y + (int)yship + (rnd()+rnd()-1)*sin(shieldpulse)*4 + 1; if (x>0 && y>0 && xpitch/2 * y + x; raw_pixels[offset] = c; } } } else { // When the shields are off, check that the black points // on the ship are still black, and not covered up by rocks for (p=black_point; ppitch/2 * (p->y + (int)yship) + p->x + (int)xship; if (raw_pixels[offset]) { // Set the bang flag bang = 1; } } } SDL_UnlockSurface(surf_screen); } #ifdef DOTCOLLISION dotcollision(surf_screen); #endif // Draw the score when playing the game or whn the game is freshly over if (1 || state==GAME_PLAY || state==DEAD_PAUSE || state==GAME_OVER ) { int scorepos; scorepos = XSIZE-250; snprintf(topline, 50, "Score: %d", score); PutString(surf_screen,scorepos,0,topline); snprintf(topline, 50, "Level: %d", (int)level); PutString(surf_screen,scorepos,20,topline); } // Draw all the little ships if (state==GAME_PLAY || state==DEAD_PAUSE || state==GAME_OVER) { for (i=0; iw; src.h = surf_small_ship->h; dest.w = src.w; dest.h = src.h; dest.x = (i+1)*(src.w+10); dest.y = 20; SDL_BlitSurface(surf_small_ship,&src,surf_screen,&dest); } // Show the shield gauge showgauge(10, surf_gauge_shield, shieldlevel/(3*W)); // Show the laser gauge showgauge(200, surf_gauge_laser, laserlevel/(3*W)); /* src.w = surf_gauge->w; src.h = surf_gauge->h; dest.w = src.w; dest.h = src.h; dest.x = 10; dest.y = YSIZE-src.h-10; SDL_BlitSurface(surf_gauge,&src,surf_screen,&dest); */ /* // Show the shield level // todo - alter the shield surface to reflect the amount of shields src.w = surf_gauge_shield->w; src.h = surf_gauge_shield->h; dest.w = src.w; dest.h = src.h; dest.x = 10; dest.y = YSIZE-src.h-10; SDL_BlitSurface(surf_gauge_shield,&src,surf_screen,&dest); // Show the laser level // todo - alter the laser surface to reflect the amount of laser power // todo - reduce the laser power after every shot src.w = surf_gauge_laser->w; src.h = surf_gauge_laser->h; dest.w = src.w; dest.h = src.h; dest.x = XSIZE-10-src.w; dest.y = YSIZE-src.h-10; SDL_BlitSurface(surf_gauge_laser,&src,surf_screen,&dest); */ } // Update the score /* n=SDL_GetTicks()-initticks; if (score) ticks_since_last = n-score; score = n; */ ticks_since_last = SDL_GetTicks()-last_ticks; last_ticks = SDL_GetTicks(); if (ticks_since_last>200 || ticks_since_last<0) { movementrate = 0; } else { movementrate = ticks_since_last/50.0; if (state==GAME_PLAY) inc_score(0,0,ticks_since_last); } // Update the surface SDL_Flip(surf_screen); return bang; }/*}}}*/ int gameloop() {/*{{{*/ int i=0; Uint8 *keystate; int inputstate[NUM_INPUTS]; SDL_Joystick *joystick; int stick_x, stick_y, button; for(;;) { if (!paused) { // Count down the game loop timer, and change state when it gets to zero or less; if ((state_timeout -= movementrate*3) < 0) { switch(state) { case DEAD_PAUSE: // Create a new ship and start all over again state = GAME_PLAY; play_tune(1); initialshield = 150; xship = 10; yship = YSIZE/2; xvel=2; yvel=0; shieldlevel = 3*W; laserlevel = 3*W; break; case GAME_OVER: state = HIGH_SCORE_ENTRY; clearBuffer(); name[0]=0; state_timeout=5.0e6; if (score>=high[7].score) { // Read the high score table from the storage file read_high_score_table(); // Find ranking of this score, store as scorerank for (i=0; i<8; i++) { if (high[i].score <= score) { scorerank = i; break; } } // Move all lower scores down a notch for (i=7; i>=scorerank; i--) high[i] = high[i-1]; // Insert blank high score high[scorerank].score = score; high[scorerank].name = ""; high[scorerank].allocated = 0; } break; case HIGH_SCORE_DISPLAY: state = TITLE_PAGE; state_timeout=500.0; break; case HIGH_SCORE_ENTRY: // state = TITLE_PAGE; // play_tune(1); // state_timeout=100.0; break; #ifdef DEMO_ENABLED case TITLE_PAGE: state = DEMO; state_timeout=100.0; break; case DEMO: state = HIGH_SCORE_DISPLAY; state_timeout=100.0; break; #else case TITLE_PAGE: state = HIGH_SCORE_DISPLAY; state_timeout=200.0; break; #endif } } if (level-(int)level < 0.8) { if (state!=GAME_PLAY) countdown -= 0.3 * movementrate; else countdown -= rockrate * movementrate; while (countdown<0) { countdown++; // Create a rock rockptr++; if (rockptr-rock>=MAX_ROCKS) rockptr=rock; if (!rockptr->active && !rockptr->greeb) { rockptr->x = (float)XSIZE; rockptr->y = rnd()*YSIZE; rockptr->xvel = -(rockspeed)*(1+rnd()); rockptr->yvel = rnd()-0.5; rockptr->type_number = random() % NROCKS; rockptr->heat = 0; rockptr->image = surf_rock[rockptr->type_number];// [random()%NROCKS]; rockptr->active = 1; } } } // Increase difficulty if (state==GAME_PLAY) level += movementrate/250; rockspeed = 5 + sqrt((int)level)/5.0; rockrate = 0.2 + sqrt((int)level)/20.0; //greebrate = 0.2 + sqrt((int)level)/20.0; // Move all the rocks for (i=0; iXSIZE-surf_ship->w) { // BOUNCE from left and right wall xship -= xvel*movementrate; xvel *= -0.99; } // BOUNCE Y if (yship<0 || yship>YSIZE-surf_ship->h) { // BOUNCE from top and bottom wall yship -= yvel; yvel *= -0.99; } if (draw() && state==GAME_PLAY) { if (oss_sound_flag) { // Play the explosion sound play_sound(0); } makebangdots(xship,yship,xvel,yvel,surf_ship,30,3); if (--nships<=0) { gameover=1; state=GAME_OVER; state_timeout = 200.0; fadetimer=0.0; faderate=movementrate; } else { state=DEAD_PAUSE; state_timeout = 100.0; } } SDL_PumpEvents(); keystate = SDL_GetKeyState(NULL); if (state!=HIGH_SCORE_ENTRY && (keystate[SDLK_q] || keystate[SDLK_ESCAPE])) { return 0; } #ifdef CHEAT if (keystate[SDLK_5]) {score += 10000; level++;} #endif if (keystate[SDLK_SPACE] && (state==HIGH_SCORE_DISPLAY || state==TITLE_PAGE || state==DEMO)) { for (i=0; i JOYSTICK_DEADZONE) { inputstate[RIGHT] |= 1; } if (stick_x < -JOYSTICK_DEADZONE) { inputstate[LEFT] |= 1; } if (stick_y > JOYSTICK_DEADZONE) { inputstate[DOWN] |= 1; } if (stick_y < -JOYSTICK_DEADZONE) { inputstate[UP] |= 1; } button = SDL_JoystickGetButton(joystick, 0); if (button == 1) { inputstate[LASER] |= 1; } button = SDL_JoystickGetButton(joystick, 1); if (button == 1) { inputstate[SHIELD] |= 1; } } if (inputstate[UP]) { yvel -= 1.5*movementrate; maneuver|=1<<3;} if (inputstate[DOWN]) { yvel += 1.5*movementrate; maneuver|=1<<1;} if (inputstate[LEFT]) { xvel -= 1.5*movementrate; maneuver|=1<<2;} if (inputstate[RIGHT]) { xvel += 1.5*movementrate; maneuver|=1;} if (inputstate[LASER]) { laser=1; } if (inputstate[FAST]) { fast=1; } if (inputstate[NOFAST]) { fast=0; } if (inputstate[SCREENSHOT]) { SDL_SaveBMP(surf_screen, "snapshot.bmp"); } shieldsup = inputstate[SHIELD]; } if (keystate && (keystate[SDLK_PAUSE] || keystate[SDLK_p])) { if (!pausedown) { paused = !paused; if (paused) { SDL_Rect src,dest; // SDL_SetAlpha(surf_t_paused, SDL_SRCALPHA, 0); src.w = surf_t_paused->w; src.h = surf_t_paused->h; dest.w = src.w; dest.h = src.h; dest.x = (XSIZE-src.w)/2; dest.y = (YSIZE-src.h)/2; SDL_BlitSurface(surf_t_paused,&src,surf_screen,&dest); // Update the surface SDL_Flip(surf_screen); } pausedown=1; } } else { pausedown=0; } } else { shieldsup = 0; paused = 0; pausedown = 0; } } // DEBUG mode to slow down the action, and see if this game is playable on a 486 if (fast) SDL_Delay (100); } }/*}}}*/ main(int argc, char **argv) {/*{{{*/ int i, x, fullscreen; fullscreen=1; oss_sound_flag=1; while ((x=getopt(argc,argv,"wsh"))>=0) switch(x) { case 's': oss_sound_flag = 0; break; case 'w': fullscreen = 0; break; case 'h': printf ("Rock Dodgers\n" " -h This help message\n" " -f Full screen\n" " -s Silent mode (no OSS sound)\n"); exit(0); break; } initrnd(); if (init(fullscreen)) { printf ("Cannot start: '%s'\n",initerror); return 1; } while(1) { for (i=0; i