JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
* main.c: wrapped call to autopilot_fix_keystates.
[vor.git] / main.c
diff --git a/main.c b/main.c
index 88d207a..91af524 100644 (file)
--- a/main.c
+++ b/main.c
@@ -41,6 +41,7 @@
 #include "score.h"
 #include "sprite.h"
 #include "sound.h"
+#include "autopilot.h"
 
 // ************************************* VARS
 // SDL_Surface global variables
@@ -58,9 +59,17 @@ SDL_Surface
 
 font *g_font;
 
-// Structure global variables
-struct enginedots edot[MAXENGINEDOTS], *dotptr = edot;
-struct bangdots bdot[MAXBANGDOTS], *bdotptr = bdot;
+struct dot {
+       int active;
+       float x, y;
+       float dx, dy;
+       float mass;   // in DOT_MASS_UNITs
+       float decay;  // rate at which to reduce mass.
+       int heat;     // heat multiplier (color).
+};
+
+struct dot edot[MAXENGINEDOTS], *dotptr = edot;
+struct dot bdot[MAXBANGDOTS];
 
 // Other global variables
 char topline[1024];
@@ -132,108 +141,11 @@ init_engine_dots() {
        }
 }
 
-void
-new_bang_dots(struct sprite *s)
-{
-       int i, n, x, y;
-       uint16_t *pixel, c;
-       uint32_t colorkey;
-       int row_inc;
-       double theta, r;
-       SDL_Surface *img = s->image;
-
-       n = 20;
-       pixel = img->pixels;
-       row_inc = img->pitch/sizeof(uint16_t) - img->w;
-       colorkey = img->format->colorkey;
-
-       if(SDL_MUSTLOCK(img)) { SDL_LockSurface(img); }
-
-       for(i=0; i<n; i++) {
-               pixel = img->pixels;
-               for(y=0; y<img->h; y++) {
-                       for(x = 0; x<img->w; x++) {
-                               c = *pixel++;
-                               if(c && c != colorkey) {
-                                       theta = frnd()*M_PI*2;
-                                       r = frnd(); r = 1 - r*r;
-
-                                       bdot[bd2].dx = 45*r*cos(theta) + s->dx;
-                                       bdot[bd2].dy = 45*r*sin(theta) + s->dy;
-                                       bdot[bd2].x = x + s->x;
-                                       bdot[bd2].y = y + s->y;
-                                       //bdot[bd2].c = (i < n-3) ? 0 : c;
-                                       bdot[bd2].life = frnd() * 99;
-                                       bdot[bd2].decay = frnd()*3 + 1;
-                                       bdot[bd2].active = 1;
-
-                                       bd2 = (bd2+1) % MAXBANGDOTS;
-                               }
-                               pixel += row_inc;
-                       }
-               }
-       }
-
-       if(SDL_MUSTLOCK(img)) { SDL_UnlockSurface(img); }
-}
-
-void
-move_bang_dots(float ticks)
-{
-       int i;
-       Sprite *hit;
-
-       for(i=0; i<MAXBANGDOTS; i++) {
-               if(!bdot[i].active) continue;
-
-               // decrement life and maybe kill
-               bdot[i].life -= bdot[i].decay * ticks/2.0;
-               if(bdot[i].life < 0) { bdot[i].active = 0; continue; }
-               
-               // move and clip
-               bdot[i].x += (bdot[i].dx - screendx)*ticks;
-               bdot[i].y += (bdot[i].dy - screendy)*ticks;
-               if(fclip(bdot[i].x, XSIZE) || fclip(bdot[i].y, YSIZE)) {
-                       bdot[i].active = 0;
-                       continue;
-               }
-
-               // check collisions
-               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; i<MAXBANGDOTS; i++) {
-               if(!bdot[i].active) continue;
-
-               pixel = pixels + row_inc*(int)(bdot[i].y) + (int)(bdot[i].x);
-               if(bdot[i].c) c = bdot[i].c; else c = heatcolor[(int)(bdot[i].life)*3];
-               *pixel = c;
-       }
-}
-
 
 void
-new_engine_dots(float time_span) {
+new_engine_dots(void) {
        int dir, i;
-       int n = time_span * ENGINE_DOTS_PER_TIC;
+       int n = t_frame * ENGINE_DOTS_PER_TIC;
        float a, r;  // angle, random length
        float dx, dy;
        float hx, hy; // half ship width/height.
@@ -254,10 +166,11 @@ new_engine_dots(float time_span) {
                                dx = r * cos(a);
                                dy = r * -sin(a);  // screen y is "backwards".
 
-                               dotptr->active = 1;
+                               dotptr->decay = 3;
+                               dotptr->heat = 6;
 
                                // dot was created at a random time during the time span
-                               time = frnd() * time_span; // this is how long ago
+                               time = frnd() * t_frame; // 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
@@ -272,82 +185,140 @@ new_engine_dots(float time_span) {
 
                                // the starting position (not speed) of the dot is calculated as
                                // though the ship were traveling at a constant speed for this
-                               // time_span.
+                               // t_frame.
                                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 = past_ship_dx + 2*dx;
                                        dotptr->dy = past_ship_dy + 20*dy;
-                                       dotptr->life = 60 * fabs(dy);
+                                       dotptr->mass = 60 * fabs(dy);
                                } else {
                                        dotptr->dx = past_ship_dx + 20*dx;
                                        dotptr->dy = past_ship_dy + 2*dy;
-                                       dotptr->life = 60 * fabs(dx);
+                                       dotptr->mass = 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;
+                               if(!fclip(dotptr->x, XSIZE) && !fclip(dotptr->y, YSIZE)) {
+                                       dotptr->active = 1;
+                                       if(dotptr - edot < MAXENGINEDOTS-1) {
+                                               dotptr++;
+                                       } else {
+                                               dotptr = edot;
+                                       }
+                               }
                        }
                }
        }
 }
 
+
 void
-move_engine_dots(float ticks) {
-       int i;
-       Sprite *hit;
+new_bang_dots(struct sprite *s)
+{
+       int i, n, x, y;
+       uint16_t *pixel, c;
+       uint32_t colorkey;
+       int row_inc;
+       double theta, r;
+       SDL_Surface *img = s->image;
 
-       for(i = 0; i<MAXENGINEDOTS; i++) {
-               if(!edot[i].active) continue;
-
-               edot[i].x += (edot[i].dx - screendx)*ticks;
-               edot[i].y += (edot[i].dy - screendy)*ticks;
-               edot[i].life -= t_frame*3;
-               if(edot[i].life < 0 || fclip(edot[i].x, XSIZE) || fclip(edot[i].y, YSIZE)) {
-                       edot[i].active = 0;
-                       continue;
+       n = 20;
+       pixel = img->pixels;
+       row_inc = img->pitch/sizeof(uint16_t) - img->w;
+       colorkey = img->format->colorkey;
+
+       if(SDL_MUSTLOCK(img)) { SDL_LockSurface(img); }
+
+       for(i=0; i<n; i++) {
+               pixel = img->pixels;
+               for(y=0; y<img->h; y++) {
+                       for(x = 0; x<img->w; x++) {
+                               c = *pixel++;
+                               if(c && c != colorkey) {
+                                       theta = frnd()*M_PI*2;
+                                       r = frnd(); r = 1 - r*r;
+
+                                       bdot[bd2].dx = 45*r*cos(theta) + s->dx;
+                                       bdot[bd2].dy = 45*r*sin(theta) + s->dy;
+                                       bdot[bd2].x = x + s->x;
+                                       bdot[bd2].y = y + s->y;
+                                       bdot[bd2].mass = frnd() * 99;
+                                       bdot[bd2].decay = frnd()*1.5 + 0.5;
+                                       bdot[bd2].heat = 3;
+                                       bdot[bd2].active = 1;
+
+                                       bd2 = (bd2+1) % MAXBANGDOTS;
+                               }
+                               pixel += row_inc;
+                       }
                }
+       }
 
-               // 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
-                               edot[i].active = 0;
-                               hit->dx += ENGINE_DOT_WEIGHT * edot[i].life * edot[i].dx / sprite_mass(hit);
-                               hit->dy += ENGINE_DOT_WEIGHT * edot[i].life * edot[i].dy / sprite_mass(hit);
-                               continue;
+       if(SDL_MUSTLOCK(img)) { SDL_UnlockSurface(img); }
+}
+
+
+void
+move_dot(struct dot *d)
+{
+       Sprite *hit;
+       float mass;
+
+       if(d->active) {
+               d->x += (d->dx - screendx) * t_frame;
+               d->y += (d->dy - screendy) * t_frame;
+               d->mass -= t_frame * d->decay;
+               if(d->mass < 0 || fclip(d->x, XSIZE) || fclip(d->y, YSIZE))
+                       d->active = 0; 
+               else {
+                       hit = pixel_collides(d->x, d->y);
+                       if(hit) if(hit->type != SHIP) {
+                               d->active = 0;
+                               mass = sprite_mass(hit);
+                               hit->dx += DOT_MASS_UNIT * d->mass * (d->dx - hit->dx) / mass;
+                               hit->dy += DOT_MASS_UNIT * d->mass * (d->dy - hit->dy) / mass;
                        }
                }
        }
 }
 
 void
-draw_engine_dots(SDL_Surface *s) {
+move_dots(void)
+{
        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; i<MAXENGINEDOTS; i++) {
-               if(!edot[i].active) continue;
+       for(i=0; i<MAXBANGDOTS; i++) move_dot(&bdot[i]);
+       for(i=0; i<MAXENGINEDOTS; i++) move_dot(&edot[i]);
+}
+
+
+void
+draw_dot(struct dot *d)
+{
+       uint16_t *pixels, *pixel;
+       int row_inc;
 
-               heatindex = edot[i].life * 6;
-               c = heatindex>3*W ? heatcolor[3*W-1] : heatcolor[heatindex];
-               pixels[row_inc*(int)(edot[i].y) + (int)(edot[i].x)] = c;
+       if(d->active) {
+               pixels = (uint16_t *) surf_screen->pixels;
+               row_inc = surf_screen->pitch / sizeof(uint16_t);
+               pixel = pixels + (int)d->y * row_inc + (int)d->x;
+               *pixel = heatcolor[min(3*W-1, (int)(d->mass * d->heat))];
        }
 }
 
 void
-draw_dots(SDL_Surface *s) {
-       if(SDL_MUSTLOCK(s)) { SDL_LockSurface(s); }
-       draw_dust(s);
-       draw_engine_dots(s);
-       draw_bang_dots(s);
-       if(SDL_MUSTLOCK(s)) { SDL_UnlockSurface(s); }
+draw_dots(void) {
+       int i;
+
+       if(SDL_MUSTLOCK(surf_screen)) { SDL_LockSurface(surf_screen); }
+       draw_dust();
+       for(i=0; i<MAXBANGDOTS; i++) draw_dot(&bdot[i]);
+       for(i=0; i<MAXENGINEDOTS; i++) draw_dot(&edot[i]);
+       if(SDL_MUSTLOCK(surf_screen)) { SDL_UnlockSurface(surf_screen); }
 }
 
 SDL_Surface *
@@ -538,7 +509,7 @@ void
 draw(void)
 {
        SDL_FillRect(surf_screen,NULL,0);  // black background
-       draw_dots(surf_screen);            // background dots
+       draw_dots();            // background dots
        draw_sprite(SPRITE(&ship));
        draw_rocks();
 
@@ -554,7 +525,7 @@ draw(void)
                        // and fall through to
                case HIGH_SCORE_DISPLAY:
                        // Display de list o high scores mon.
-                       display_scores(surf_screen, 150,50);
+                       display_scores(150,50);
                        break;
                case GAMEPLAY:
                case DEAD_PAUSE:
@@ -611,9 +582,9 @@ init_score_entry(void)
 
 // Count down the state timer, and change state when it gets to zero or less;
 void
-update_state(float ticks)
+update_state(void)
 {
-       state_timeout -= ticks*3;
+       state_timeout -= t_frame*3;
        if(state_timeout > 0) return;
 
        switch(state) {
@@ -654,12 +625,16 @@ gameloop() {
        for(;;) {
                ms_frame = SDL_GetTicks() - ms_end;
                ms_end += ms_frame;
-               if(ms_frame > 1000) {
-                       ms_frame = 1000;
+               if(ms_frame > 50) {
+                       ms_frame = 50;
                }
                t_frame = gamespeed * ms_frame / 50;
                frames++;
 
+               if(opt_autopilot) {
+                       autopilot(t_frame);
+               }
+
                while(SDL_PollEvent(&e)) {
                        switch(e.type) {
                                case SDL_QUIT: return;
@@ -684,6 +659,9 @@ gameloop() {
                        }
                }
                keystate = SDL_GetKeyState(NULL);
+               if(opt_autopilot) {
+                       autopilot_fix_keystates(keystate);
+               }
 
                if(state == GAMEPLAY) {
                        if(!paused) {
@@ -693,6 +671,10 @@ gameloop() {
                                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(ship.jets) {
+                                       ship.dx = fconstrain2(ship.dx, -50, 50);
+                                       ship.dy = fconstrain2(ship.dy, -50, 50);
+                               }
                                if(keystate[SDLK_3])            { SDL_SaveBMP(surf_screen, "snapshot.bmp"); }
                        }
 
@@ -708,7 +690,7 @@ gameloop() {
                }
 
                if(!paused) {
-                       update_state(t_frame);
+                       update_state();
 
                        // SCROLLING
                        tmp = (ship.y+ship.h/2 + ship.dy*t_frame - YSCROLLTO)/25 + (ship.dy-screendy);
@@ -722,25 +704,31 @@ gameloop() {
                        dist_ahead += (screendx - BARRIER_SPEED)*t_frame;
                        if(MAX_DIST_AHEAD >= 0) dist_ahead = min(dist_ahead, MAX_DIST_AHEAD);
 
-                       move_sprites(t_frame);  new_rocks(t_frame);
-                       move_engine_dots(t_frame); new_engine_dots(t_frame);
-                       move_bang_dots(t_frame);
-                       move_dust(t_frame);
+                       move_sprites();
+                       move_dots();
+                       move_dust();
 
-                       collisions();
+                       new_rocks();
 
                        // BOUNCE off left or right edge of screen
                        if(ship.x < 0 || ship.x+ship.w > XSIZE) {
                                ship.x -= (ship.dx-screendx)*t_frame;
                                ship.dx = screendx - (ship.dx-screendx)*BOUNCINESS;
+                               ship.x = fconstrain(ship.x, XSIZE - ship.w);
                        }
 
                        // BOUNCE off top or bottom of screen
                        if(ship.y < 0 || ship.y+ship.h > YSIZE) {
                                ship.y -= (ship.dy-screendy)*t_frame;
                                ship.dy = screendy - (ship.dy-screendy)*BOUNCINESS;
+                               ship.y = fconstrain(ship.y, YSIZE - ship.h);
                        }
 
+                       new_engine_dots();
+
+                       collisions(); // must happen after ship bouncing because it puts pixels where the ship is (thus the ship must be on the screen)
+
+
                        draw();
 
                        // new game
@@ -803,7 +791,7 @@ main(int argc, char **argv) {
        frames = 0;
        gameloop();
        end = SDL_GetTicks();
-       // printf("%ld frames in %ld ms, %.2f fps.\n", frames, end-start, frames * 1000.0 / (end-start));
+       printf("%ld frames in %ld ms, %.2f fps.\n", frames, end-start, frames * 1000.0 / (end-start));
 
        return 0;
 }