X-Git-Url: https://jasonwoof.com/gitweb/?p=vor.git;a=blobdiff_plain;f=main.c;h=ba1c8b7bd6421c71f35543fd8da979fa5eedda50;hp=b8b03c376f3b315e8ceff72eccec572595eb4d2f;hb=ae2d57cc5b1b64621a76aed51ce14f4c555c3bc8;hpb=f1cd2ff38dd9f3c5c4925d8a5f9588129b3bf343 diff --git a/main.c b/main.c index b8b03c3..ba1c8b7 100644 --- a/main.c +++ b/main.c @@ -19,7 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -42,6 +41,10 @@ #include "sprite.h" #include "sound.h" +#ifdef WIN32 +#define SDL_SetAlpha(surf, flag, alpha) +#endif + // ************************************* VARS // SDL_Surface global variables SDL_Surface @@ -72,7 +75,7 @@ float screendx = SCREENDXMIN, screendy = 0.0; float back_dist; // all movement is based on t_frame. -float t_frame; // length of this frame (in ticks = 1/20th second) +float t_frame; // length of this frame (in ticks = 1/20th second) adjusted for gamespeed int ms_frame; // length of this frame (milliseconds) int ms_end; // end of this frame (milliseconds) @@ -99,10 +102,18 @@ enum states { enum states state = TITLE_PAGE; float state_timeout = 600.0; -#define NSEQUENCE 2 -char *sequence[] = { - "Press SPACE to start", - "http://jasonwoof.org/vor" +#define NSEQUENCE 3 +char *msgs[2][3] = { + { + "Press SPACE for normal game", + "Press '1' for easy game", + "http://jasonwoof.org/vor" + }, + { + "Press SPACE for easy game", + "Press '2' for normal game", + "http://jasonwoof.org/vor" + } }; int bangdotlife, nbangdots; @@ -127,22 +138,20 @@ init_engine_dots() { void new_bang_dots(int xbang, int ybang, int dx, int dy, SDL_Surface *s) { - int x,y,endcount; - uint16_t *pixel,c; + int i, n, x, y; + uint16_t *pixel, c; uint32_t colorkey; int row_inc; - double theta,r; - int begin_generate; + double theta, r; - begin_generate = SDL_GetTicks(); + n = 24.0 * t_frame; pixel = s->pixels; row_inc = s->pitch/sizeof(uint16_t) - s->w; colorkey = s->format->colorkey; SDL_LockSurface(s); - endcount = 0; - while (endcount<3) { + for(i=0; ipixels; for(y=0; yh; y++) { for(x = 0; xw; x++) { @@ -150,60 +159,71 @@ new_bang_dots(int xbang, int ybang, int dx, int dy, SDL_Surface *s) if(c && c != colorkey) { theta = frnd()*M_PI*2; r = frnd(); r = 1 - r*r; - // r = 1 - frnd()*frnd(); bdot[bd2].dx = 45*r*cos(theta) + dx; bdot[bd2].dy = 45*r*sin(theta) + dy; bdot[bd2].x = x + xbang; bdot[bd2].y = y + ybang; - bdot[bd2].c = 0; + bdot[bd2].c = (i < n-3) ? 0 : c; bdot[bd2].life = 100; bdot[bd2].decay = frnd()*3 + 1; bdot[bd2].active = 1; - // Replace the last few bang dots with the pixels from the exploding object - if(endcount>0) bdot[bd2].c = c; - bd2 = (bd2+1) % MAXBANGDOTS; } pixel += row_inc; } } - if(SDL_GetTicks() - begin_generate > 7) endcount++; } SDL_UnlockSurface(s); } void -draw_bang_dots(SDL_Surface *s) +move_bang_dots(float ticks) { int i; - int first_i, last_i; - uint16_t *pixels, *pixel, c; - int row_inc = s->pitch/sizeof(uint16_t); - - pixels = (uint16_t *) s->pixels; - first_i = -1; - last_i = 0; + Sprite *hit; for(i=0; i= XSIZE || bdot[i].y < 0 || bdot[i].y >= YSIZE) { bdot[i].active = 0; continue; } // check collisions - if(pixel_collides(bdot[i].x, bdot[i].y)) { bdot[i].active = 0; continue; } + if((hit = pixel_collides(bdot[i].x, bdot[i].y))) { + if(hit->type != SHIP) { // they shouldn't hit the ship, but they do + bdot[i].active = 0; + hit->dx += ENGINE_DOT_WEIGHT * bdot[i].life * bdot[i].dx / sprite_mass(hit); + hit->dy += ENGINE_DOT_WEIGHT * bdot[i].life * bdot[i].dy / sprite_mass(hit); + continue; + } + } + } +} + + +void +draw_bang_dots(SDL_Surface *s) +{ + int i; + uint16_t *pixels, *pixel, c; + int row_inc = s->pitch/sizeof(uint16_t); + + pixels = (uint16_t *) s->pixels; + + for(i=0; iw / 2; hy = ship.image->h / 2; @@ -231,18 +254,40 @@ new_engine_dots(int n, int dir) { dy = r * -sin(a); // screen y is "backwards". dotptr->active = 1; - dotptr->x = ship.x + s[dir]*hx + (frnd()-0.5)*3; - dotptr->y = ship.y + s[(dir+1)&3]*hy + (frnd()-0.5)*3; + + // dot was created at a random time during the time span + time = frnd() * time_span; // this is how long ago + + // calculate how fast the ship was going when this engine dot was + // created (as if it had a smooth acceleration). This is used in + // determining the velocity of the dots, but not their starting + // location. + accelh = ((ship.jets >> 2) & 1) - (ship.jets & 1); + accelh *= THRUSTER_STRENGTH * time; + past_ship_dx = ship.dx - accelh; + accelv = ((ship.jets >> 1) & 1) - ((ship.jets >> 3) & 1); + accelv *= THRUSTER_STRENGTH * time; + past_ship_dy = ship.dy - accelv; + + // the starting position (not speed) of the dot is calculated as + // though the ship were traveling at a constant speed for this + // time_span. + dotptr->x = (ship.x - (ship.dx - screendx) * time) + s[dir]*hx; + dotptr->y = (ship.y - (ship.dy - screendy) * time) + s[(dir+1)&3]*hy; if(dir&1) { - dotptr->dx = ship.dx + 2*dx; - dotptr->dy = ship.dy + 20*dy; + dotptr->dx = past_ship_dx + 2*dx; + dotptr->dy = past_ship_dy + 20*dy; dotptr->life = 60 * fabs(dy); } else { - dotptr->dx = ship.dx + 20*dx; - dotptr->dy = ship.dy + 2*dy; + dotptr->dx = past_ship_dx + 20*dx; + dotptr->dy = past_ship_dy + 2*dy; dotptr->life = 60 * fabs(dx); } + // move the dot as though it were created in the past + dotptr->x += (dotptr->dx - screendx) * time; + dotptr->y += (dotptr->dy - screendy) * time; + if(dotptr - edot < MAXENGINEDOTS-1) dotptr++; else dotptr = edot; } @@ -250,25 +295,20 @@ new_engine_dots(int n, int dir) { } void -draw_engine_dots(SDL_Surface *s) { +move_engine_dots(float ticks) { int i; - uint16_t c; - uint16_t *pixels = (uint16_t *) s->pixels; - int row_inc = s->pitch/sizeof(uint16_t); - int heatindex; Sprite *hit; for(i = 0; i= XSIZE - || edot[i].y<0 || edot[i].y >= YSIZE) { + if(edot[i].life < 0 || edot[i].x<0 || edot[i].x >= XSIZE || edot[i].y < 0 || edot[i].y >= YSIZE) { edot[i].active = 0; - continue; } + // check collisions if((hit = pixel_collides(edot[i].x, edot[i].y))) { if(hit->type != SHIP) { // they shouldn't hit the ship, but they do @@ -278,6 +318,20 @@ draw_engine_dots(SDL_Surface *s) { continue; } } + } +} + +void +draw_engine_dots(SDL_Surface *s) { + int i; + uint16_t c; + uint16_t *pixels = (uint16_t *) s->pixels; + int row_inc = s->pitch/sizeof(uint16_t); + int heatindex; + + for(i = 0; i3*W ? heatcolor[3*W-1] : heatcolor[heatindex]; pixels[row_inc*(int)(edot[i].y) + (int)(edot[i].x)] = c; @@ -285,18 +339,16 @@ draw_engine_dots(SDL_Surface *s) { } void -drawdots(SDL_Surface *s) { +draw_dots(SDL_Surface *s) { int m; - // Create engine dots out the side we're moving from + // Create engine dots for(m = 0; m<4; m++) { if(ship.jets & 1<h)/2 + 40; SDL_SetAlpha(surf_b_over, SDL_SRCALPHA, (int)(a_over*(200 + 55*sin(fadetimer)))); SDL_BlitSurface(surf_b_over,NULL,surf_screen,&dest); + + if(new_high_score(score)) { + text0 = "New High Score!"; + text1 = "Press SPACE to continue"; + } else { + text0 = msgs[g_easy][0]; + text1 = msgs[g_easy][1]; + } + + x = (XSIZE-SFont_TextWidth(g_font,text0))/2 + cos(fadetimer/9)*10; + SFont_Write(surf_screen,g_font,x,YSIZE-100 + cos(fadetimer/6)*5,text0); + + x = (XSIZE-SFont_TextWidth(g_font,text1))/2 + sin(fadetimer/9)*10; + SFont_Write(surf_screen,g_font,x,YSIZE-50 + sin(fadetimer/4)*5,text1); } void @@ -467,20 +535,20 @@ draw_title_page(void) SDL_SetAlpha(surf_b_rockdodger, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer-2.0))); SDL_BlitSurface(surf_b_rockdodger,NULL,surf_screen,&dest); + text = msgs[g_easy][(int)(fadetimer/35)%NSEQUENCE]; + x = (XSIZE-SFont_TextWidth(g_font,text))/2 + cos(fadetimer/4.5)*10; + SFont_Write(surf_screen,g_font,x,YSIZE-100 + cos(fadetimer/3)*5,text); + text = "Version " VERSION; x = (XSIZE-SFont_TextWidth(g_font,text))/2 + sin(fadetimer/4.5)*10; SFont_Write(surf_screen,g_font,x,YSIZE-50 + sin(fadetimer/2)*5,text); - - text = sequence[(int)(fadetimer/40)%NSEQUENCE]; - x = (XSIZE-SFont_TextWidth(g_font,text))/2 + cos(fadetimer/4.5)*10; - SFont_Write(surf_screen,g_font,x,YSIZE-100 + cos(fadetimer/3)*5,text); } void draw(void) { SDL_FillRect(surf_screen,NULL,0); // black background - drawdots(surf_screen); // background dots + draw_dots(surf_screen); // background dots draw_sprite(SPRITE(&ship)); draw_rocks(); @@ -495,17 +563,6 @@ draw(void) { case HIGH_SCORE_ENTRY: play_tune(TUNE_HIGH_SCORE_ENTRY); - if(!process_score_input()) { // done inputting name - - // 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_tune(TUNE_TITLE_PAGE); - } // FALL THROUGH TO case HIGH_SCORE_DISPLAY: // Display de list o high scores mon. @@ -531,8 +588,6 @@ static inline void kill_ship(Sprite *ship) { ship->flags = MOVE; - // ship->flags = MOVE|DRAW; // FADE SHIP - // SDL_SetAlpha(ship->image, SDL_SRCALPHA, 0); // FADE SHIP bang = true; } @@ -553,16 +608,38 @@ init_score_entry(void) SDL_EnableUNICODE(1); while(SDL_PollEvent(&e)) ; + insert_score(score); } void gameloop() { - Uint8 *keystate = SDL_GetKeyState(NULL); + SDL_Event e; + Uint8 *keystate; float tmp; for(;;) { - SDL_PumpEvents(); + while(SDL_PollEvent(&e)) { + switch(e.type) { + case SDL_QUIT: return; + case SDL_KEYUP: + if(e.key.keysym.sym == SDLK_ESCAPE + || e.key.keysym.sym == SDLK_q) + return; + break; + case SDL_KEYDOWN: + if(state == HIGH_SCORE_ENTRY) + if(!process_score_input(&e.key.keysym)) { + // Write the high score table to the file + write_high_score_table(); + // continue to display the scores briefly + state = HIGH_SCORE_DISPLAY; + state_timeout = 200; + play_tune(TUNE_TITLE_PAGE); + } + break; + } + } keystate = SDL_GetKeyState(NULL); if(!paused) { @@ -585,7 +662,8 @@ gameloop() { break; case HIGH_SCORE_DISPLAY: state = TITLE_PAGE; - state_timeout = 500.0; + state_timeout = 600.0; + fadetimer = 0.0; break; case HIGH_SCORE_ENTRY: break; @@ -598,27 +676,14 @@ gameloop() { } } else { if(state == DEAD_PAUSE) { - float blast_radius; - // float alpha; // FADE SHIP - if(state_timeout >= DEAD_PAUSE_LENGTH - 20.0) { - blast_radius = BLAST_RADIUS * (DEAD_PAUSE_LENGTH - state_timeout) / 20.0; - blast_rocks(bangx, bangy, blast_radius); - } - if(bangx < 60) bangx = 60; - - // FADE SHIP - // alpha = 255.0 * (DEAD_PAUSE_LENGTH - state_timeout) / DEAD_PAUSE_LENGTH; - // SDL_SetAlpha(ship.image, SDL_SRCALPHA, (uint8_t)alpha); } } - new_rocks(); - // SCROLLING - tmp = (ship.y+ship.dy*t_frame-YSCROLLTO)/25 + (ship.dy-screendy); + tmp = (ship.y+ship.h/2+ship.dy*t_frame-YSCROLLTO)/25 + (ship.dy-screendy); screendy += tmp * t_frame/12; - tmp = (ship.x+ship.dx*t_frame-XSCROLLTO)/25 + (ship.dx-screendx); + tmp = (ship.x+ship.w/2+ship.dx*t_frame-XSCROLLTO)/25 + (ship.dx-screendx); screendx += tmp * t_frame/12; // taper off so we don't hit the barrier abruptly. // (if we would hit in < 2 seconds, adjust to 2 seconds). @@ -631,8 +696,10 @@ gameloop() { bangx += (bangdx - screendx)*t_frame; bangy += (bangdy - screendy)*t_frame; - move_sprites(); - + move_sprites(t_frame); + move_engine_dots(t_frame); + move_bang_dots(t_frame); + move_dust(t_frame); // BOUNCE off left or right edge of screen if(ship.x < 0 || ship.x+ship.w > XSIZE) { @@ -646,6 +713,8 @@ gameloop() { ship.dy = screendy - (ship.dy-screendy)*opt_bounciness; } + new_rocks(t_frame); + draw(); if(state == GAMEPLAY && bang) { @@ -671,13 +740,25 @@ gameloop() { } // new game - if(keystate[SDLK_SPACE] + if((keystate[SDLK_SPACE] || keystate[SDLK_1] || keystate[SDLK_2]) && (state == HIGH_SCORE_DISPLAY || state == TITLE_PAGE || state == GAME_OVER)) { if(state == GAME_OVER && new_high_score(score)) init_score_entry(); else { + if((keystate[SDLK_SPACE] && !initial_rocks) || keystate[SDLK_2]) { + g_easy = 0; + initial_rocks = NORMAL_I_ROCKS; + final_rocks = NORMAL_F_ROCKS; + if(opt_gamespeed == EASY_GAMESPEED) + opt_gamespeed = NORMAL_GAMESPEED; + } else if(keystate[SDLK_1]) { + g_easy = 1; + initial_rocks = EASY_I_ROCKS; + final_rocks = EASY_F_ROCKS; + opt_gamespeed = EASY_GAMESPEED; + } reset_sprites(); reset_rocks(); screendx = SCREENDXMIN; screendy = 0; @@ -686,7 +767,6 @@ gameloop() { ship.dx = screendx; ship.dy = screendy; ship.lives = 4; ship.flags = MOVE|DRAW|COLLIDE; - // SDL_SetAlpha(ship.image, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); // FADE SHIP add_sprite(SPRITE(&ship)); score = 0; @@ -701,10 +781,11 @@ gameloop() { if(state == GAMEPLAY) { if(!paused) { - if(keystate[SDLK_LEFT] | keystate[SDLK_h]) { ship.dx -= 1.5*t_frame; ship.jets |= 1<<0;} - if(keystate[SDLK_DOWN] | keystate[SDLK_t]) { ship.dy += 1.5*t_frame; ship.jets |= 1<<1;} - if(keystate[SDLK_RIGHT] | keystate[SDLK_n]) { ship.dx += 1.5*t_frame; ship.jets |= 1<<2;} - if(keystate[SDLK_UP] | keystate[SDLK_c]) { ship.dy -= 1.5*t_frame; ship.jets |= 1<<3;} + // FIXME why is this at the bottom? Shouldn't it be up before the ship movement? + if(keystate[SDLK_LEFT] || keystate[SDLK_h]) { ship.dx -= THRUSTER_STRENGTH*t_frame; ship.jets |= 1<<0;} + if(keystate[SDLK_DOWN] || keystate[SDLK_t]) { ship.dy += THRUSTER_STRENGTH*t_frame; ship.jets |= 1<<1;} + if(keystate[SDLK_RIGHT] || keystate[SDLK_n]) { ship.dx += THRUSTER_STRENGTH*t_frame; ship.jets |= 1<<2;} + if(keystate[SDLK_UP] || keystate[SDLK_c]) { ship.dy -= THRUSTER_STRENGTH*t_frame; ship.jets |= 1<<3;} if(keystate[SDLK_3]) { SDL_SaveBMP(surf_screen, "snapshot.bmp"); } } @@ -719,16 +800,16 @@ gameloop() { } } - if(state != HIGH_SCORE_ENTRY && (keystate[SDLK_q] || keystate[SDLK_ESCAPE])) - return; - + if(state == TITLE_PAGE && keystate[SDLK_h]) { + state = HIGH_SCORE_DISPLAY; + state_timeout = 400; + } } } int main(int argc, char **argv) { - init_opts(); - argp_parse(&argp, argc, argv, 0, 0, 0); + if(!parse_opts(argc, argv)) return 1; if(init()) { printf ("ta: '%s'\n",initerror);