1 /* Variations on RockDodger
2 * Space Rocks copyright (C) 2001 Paul Holt <pad@pcholt.com>
4 * Project fork 2004, Jason Woofenden and Joshua Grams.
5 * (a whole bunch of modifications and project rename)
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 extern int font_height;
29 #include <SDL/SDL_image.h>
36 #include <sys/types.h>
45 #define NROCKS 6 // Number of rock image files, not number of rocks visible
46 #define MAXROCKS 120 // MAX Rocks
47 #define MAXROCKHEIGHT 100
49 #define MAXBLACKPOINTS 500
50 #define MAXENGINEDOTS 5000
51 #define MAXBANGDOTS 50000
52 #define MAXSPACEDOTS 2000
55 #define BIG_FONT_FILE "fonts/score.png"
58 #define CONDERROR(a) if ((a)) {initerror=strdup(SDL_GetError());return 1;}
59 #define NULLERROR(a) CONDERROR((a)==NULL)
62 // ************************************* STRUCTS
63 struct rock_struct {/*{{{*/
64 // Array of black pixel coordinates. This is scanned
65 // every frame to see if it's still black, and as
66 // soon as it isn't we BLOW UP
73 struct black_point_struct {/*{{{*/
76 struct bangdots {/*{{{*/
77 // Bang dots have the same colour as shield dots.
78 // Bang dots get darker as they age.
79 // Some are coloured the same as the ex-ship.
81 Uint16 c; // when zero, use heatcolor[bangdotlife]
82 float life; // When reduced to 0, set active=0
84 float decay;// Amount by which to reduce life each time dot is drawn
86 struct enginedots {/*{{{*/
87 // Engine dots stream out the back of the ship, getting darker as they go.
90 // The life of an engine dot
91 // is a number starting at between 0 and 50 and counting backward.
92 float life; // When reduced to 0, set active=0
94 struct spacedot {/*{{{*/
95 // Space dots are harmless background items
96 // All are active. When one falls off the edge, another is created at the start.
100 // High score table {{{
117 // ************************************* VARS
118 // SDL_Surface global variables {{{
120 *surf_screen, // Screen
121 *surf_b_variations, // "variations" banner
122 *surf_b_on, // "on" banner
123 *surf_b_rockdodger, // "rockdodger" banner
124 *surf_b_game, // Title element "game"
125 *surf_b_over, // Title element "over"
126 *surf_ship, // Spaceship element
127 *surf_life, // Indicator of number of ships remaining
128 *surf_rock[NROCKS], // THE ROCKS
129 *surf_deadrock[NROCKS], // THE DEAD ROCKS
130 *surf_font_big; // The big font
132 // Structure global variables {{{
133 struct enginedots edot[MAXENGINEDOTS], *dotptr=edot;
134 struct rock_struct rock[MAXROCKS], *rockptr=rock;
135 struct black_point_struct black_point[MAXBLACKPOINTS], *blackptr=black_point;
136 struct bangdots bdot[MAXBANGDOTS], *bdotptr=bdot;
137 struct spacedot sdot[MAXSPACEDOTS];
139 // Other global variables {{{
141 char *initerror = "";
142 char name[1024], debug1[1024];
144 float xship,yship = 240.0; // X position, 0..XSIZE
145 float xvel,yvel; // Change in X position per tick.
146 float rockrate,rockspeed;
148 float shieldlevel, shieldpulse=0;
151 int nships,score,initticks,ticks_since_last, last_ticks;
152 int initialshield, gameover, fast;
157 int oss_sound_flag=0;
158 int tail_plume=0; // display big engine at the back?
159 int friction=0; // should there be friction?
161 float fadetimer=0,faderate;
163 int pausedown=0,paused=0;
165 // bangdot start (bd1) and end (bd2) position:
168 int xoffset[NROCKS][MAXROCKHEIGHT];
179 enum states state=TITLE_PAGE;
180 float state_timeout = 600.0;
182 const int fakesin[] = {0,1,0,-1};
183 const int fakecos[] = {1,0,-1,0};
186 "Press SPACE to start",
187 "http://qualdan.com/vor/"
190 int bangdotlife, nbangdots;
191 Uint16 heatcolor[W*3];
195 extern int optind, opterr, optopt;
198 // ************************************* FUNCS
200 int dotcollision(SDL_Surface *s) {/*{{{*/
202 Uint16 *rawpixel, *r;
205 * Kill all the dots which collide with other objects.
206 * This does not work, it's probably in the wrong place or something.
209 rawpixel = (Uint16 *) s->pixels;
210 if (bangdotlife > 0 && bangdotlife<80) {
211 for (i=0; i<nbangdots; i++) {
212 if (bdot[i].x>0 && bdot[i].x<XSIZE && bdot[i].y>0 && bdot[i].y<YSIZE) {
213 r = &rawpixel[(int)(s->pitch/2*(int)(bdot[i].y))+(int)(bdot[i].x)];
214 if (*r != (bdot[i].c ? bdot[i].c : heatcolor[bangdotlife*2]))
219 SDL_UnlockSurface(s);
225 FILE *hs_fopen(char *mode) {/*{{{*/
229 if (f=fopen("/usr/share/vor/.highscore",mode)) {
236 sprintf(s,"%s/.vor-high",getenv("HOME"));
237 if (f=fopen(s,mode)) {
247 void read_high_score_table() {/*{{{*/
250 if (f=hs_fopen("r")) {
251 // If the file exists, read from it
252 for (i=0; i<8; i++) {
255 if (fscanf (f, "%d %[^\n]", &highscore, s)!=2)
257 if (high[i].allocated)
259 high[i].name = strdup(s);
260 high[i].score = highscore;
261 high[i].allocated = 1;
266 void write_high_score_table() {/*{{{*/
269 if (f=hs_fopen("w")) {
270 // If the file exists, write to it
271 for (i=0; i<8; i++) {
272 fprintf (f, "%d %s\n", high[i].score, high[i].name);
277 void snprintscore(char *s, size_t n, int score) {/*{{{*/
278 int min = score/60000;
279 int sec = score/1000%60;
280 int tenths = score%1000/100;
282 snprintf(s, n, "%2d:%.2d.%d", min, sec, tenths);
284 snprintf(s, n, " %2d.%d", sec, tenths);
288 return (float)random()/(float)RAND_MAX;
290 void init_engine_dots() {/*{{{*/
292 for (i=0; i<MAXENGINEDOTS; i++) {
296 void init_space_dots() {/*{{{*/
298 for (i=0; i<MAXSPACEDOTS; i++) {
301 sdot[i].x = rnd()*(XSIZE-5);
302 sdot[i].y = rnd()*(YSIZE-5);
308 intensity = (int)(r*180+70);
309 sdot[i].color = SDL_MapRGB(surf_screen->format,intensity,intensity,intensity);
314 int drawlaser() {/*{{{*/
320 // let xc = x coordinate of the collision between the laser and a space rock
321 // 1. Calculate xc and determine the asteroid that was hit
322 for (i=0; i<MAXROCKS; i++) {
323 if (rock[i].active) {
324 if (yship+12>rock[i].y && yship+12<rock[i].y+rock[i].image->h && xship+32<rock[i].x+(rock[i].image->w/2) && rock[i].x+(rock[i].image->w/2) < xc) {
325 xc = rock[i].x+(rock[i].image->w/2);
332 rock[hitrock].heat += movementrate*3;
335 // Plot a number of random dots between xship and XSIZE
336 SDL_LockSurface(surf_screen);
337 rawpixel = (Uint16 *) surf_screen->pixels;
338 c = SDL_MapRGB(surf_ship->format,rnd()*128,128+rnd()*120,rnd()*128);
340 for (i=0; i<(xc-xship)*5; i+=10) {
342 x = rnd()*(xc-(xship+32))+xship+32;
343 y = yship+12+(rnd()-0.5)*1.5;
344 rawpixel[surf_screen->pitch/2*y+x]=c;
347 SDL_UnlockSurface(surf_screen);
351 int makebangdots(int xbang, int ybang, int xvel, int yvel, SDL_Surface *s, int power) {/*{{{*/
353 // TODO - stop generating dots after a certain amount of time has passed, to cope with slower CPUs.
354 // TODO - generate and display dots in a circular buffer
356 int i,x,y,n,endcount;
358 double theta,r,dx,dy;
361 begin_generate = SDL_GetTicks();
364 rawpixel = (Uint16 *) s->pixels;
366 //for (n=0; n<=power/2; n++) {
371 for (x=0; x<s->w; x++) {
372 for (y=0; y<s->h; y++) {
373 c = rawpixel[s->pitch/2*y+x];
374 if (c && c != SDL_MapRGB(s->format,0,255,0)) {
376 theta = rnd()*M_PI*2;
380 bdot[bd2].dx = (power/50.0)*45.0*cos(theta)*r+xvel;
381 bdot[bd2].dy = (power/50.0)*45.0*sin(theta)*r+yvel;
382 bdot[bd2].x = x+xbang;
383 bdot[bd2].y = y+ybang;
385 // Replace the last few bang dots with the pixels from the exploding object
386 bdot[bd2].c = (endcount>0)?c:0;
387 bdot[bd2].life = 100;
388 bdot[bd2].decay = rnd()*3+1;
389 bdot[bd2].active = 1;
394 // If the circular buffer is filled, who cares? They've had their chance.
395 //if (bd2==bd1-1) goto exitloop;
401 if (SDL_GetTicks() - begin_generate > 7) endcount++;
406 SDL_UnlockSurface(s);
410 void draw_bang_dots(SDL_Surface *s) {/*{{{*/
414 rawpixel = (Uint16 *) s->pixels;
418 for (i=bd1; (bd1<=bd2)?(i<bd2):(i>=bd1 && i<bd2); last_i = ++i) {
422 if (bdot[i].x<=0 || bdot[i].x>=XSIZE || bdot[i].y<=0 || bdot[i].y>=YSIZE) {
423 // If the dot has drifted outside the perimeter, kill it
427 if (bdot[i].active) {
429 //printf("%d %d\n",bd1,bd2);
434 rawpixel[(int)(s->pitch/2*(int)(bdot[i].y))+(int)(bdot[i].x)]
435 = bdot[i].c ? bdot[i].c : heatcolor[(int)(bdot[i].life*3)];
436 bdot[i].life-=bdot[i].decay;
437 bdot[i].x += bdot[i].dx*movementrate;
438 bdot[i].y += bdot[i].dy*movementrate + yscroll;
452 //printf("new %d %d\n",bd1,bd2);
453 //fprintf (stderr,"%d - %d\n", bd1,bd2);
458 //fprintf (stderr,"reset\n");
464 void draw_space_dots(SDL_Surface *s) {/*{{{*/
467 rawpixel = (Uint16 *) s->pixels;
469 for (i=0; i<MAXSPACEDOTS; i++) {
470 if (sdot[i].y<0) sdot[i].y=0;
471 rawpixel[(int)(s->pitch/2*(int)sdot[i].y)+(int)(sdot[i].x)] = sdot[i].color;
472 sdot[i].x += sdot[i].dx*movementrate;
473 sdot[i].y += yscroll;
474 if(sdot[i].y > YSIZE) {
476 } else if(sdot[i].y < 0) {
483 void draw_engine_dots(SDL_Surface *s) {/*{{{*/
486 rawpixel = (Uint16 *) s->pixels;
488 for (i=0; i<MAXENGINEDOTS; i++) {
489 if (edot[i].active) {
490 edot[i].x += edot[i].dx*movementrate;
491 edot[i].y += edot[i].dy*movementrate + yscroll;
492 if ((edot[i].life-=movementrate*3)<0 || edot[i].y<0 || edot[i].y>YSIZE)
495 if (edot[i].x<0 || edot[i].x>XSIZE) {
500 heatindex = edot[i].life * 6;
501 //rawpixel[(int)(s->pitch/2*(int)(edot[i].y))+(int)(edot[i].x)] = lifecolor[(int)(edot[i].life)];
502 rawpixel[(int)(s->pitch/2*(int)(edot[i].y))+(int)(edot[i].x)] = heatindex>3*W ? heatcolor[3*W-1] : heatcolor[heatindex];
508 void create_engine_dots(int newdots) {
510 double theta,r,dx,dy;
512 if(!tail_plume) return;
515 for (i=0; i<newdots*movementrate; i++) {
516 if (dotptr->active==0) {
518 theta = rnd()*M_PI*2;
524 dotptr->x=xship+surf_ship->w/2-14;
525 dotptr->y=yship+surf_ship->h/2+(rnd()-0.5)*5-1;
526 dotptr->dx=10*(dx-1.5)+xvel;
527 dotptr->dy=1*dy+yvel;
528 dotptr->life=45+rnd(1)*5;
531 if (dotptr-edot>=MAXENGINEDOTS) dotptr = edot;
537 void create_engine_dots2(int newdots, int m) {
539 double theta, theta2, dx, dy, adx, ady;
541 // Don't create fresh engine dots when
542 // the game is not being played and a demo is not beng shown
543 if (state!=GAMEPLAY && state!=DEMO) return;
545 for (i=0; i<newdots; i++) {
546 if (dotptr->active==0) {
548 theta = rnd()*M_PI*2;
549 theta2 = rnd()*M_PI*2;
551 dx = cos(theta) * fabs(cos(theta2));
552 dy = sin(theta) * fabs(cos(theta2));
558 dotptr->x=xship+surf_ship->w/2+(rnd()-0.5)*3;
559 dotptr->y=yship+surf_ship->h/2+(rnd()-0.5)*3;
564 dotptr->dx=-20*adx + xvel;
565 dotptr->dy=2*dy+yvel;
566 dotptr->life = 60 * adx;
569 dotptr->dx=2*dx+xvel;
570 dotptr->dy=-20*ady + yvel;
571 dotptr->life = 60 * ady;
575 dotptr->dx=20*adx + xvel;
576 dotptr->dy=2*dy+yvel;
577 dotptr->life = 60 * adx;
580 dotptr->dx=2*dx+xvel;
581 dotptr->dy=20*ady + yvel;
582 dotptr->life = 60 * ady;
585 //dotptr->life *= 0.5 + rnd(0.5);
586 //dotptr->life=45+rnd(1)*20;
588 if (dotptr-edot>=MAXENGINEDOTS)
594 int drawdots(SDL_Surface *s) {/*{{{*/
598 // Draw the background stars aka space dots
601 // Draw the score when playing the game or whn the game is freshly over
602 if (1 || state==GAMEPLAY || state==DEAD_PAUSE || state==GAME_OVER ) {
604 SDL_UnlockSurface(s);
606 scorepos = XSIZE-250;
607 n = snprintf(topline, 50, "Time: ");
608 snprintscore(topline+n, 50-n, score);
609 PutString(s,scorepos,0,topline);
615 // Draw all the engine dots
618 // Create more engine dots comin out da back
620 create_engine_dots(200);
622 // Create engine dots out the side we're moving from
624 if (maneuver & 1<<m) // 'maneuver' is a bit field
625 create_engine_dots2(80,m);
627 // Draw all outstanding bang dots
628 //if (bangdotlife-- > 0)
631 SDL_UnlockSurface(s);
633 char * load_file(char *s) {/*{{{*/
634 static char retval[1024];
635 snprintf(retval, 1024, "%s/%s", data_dir, s);
639 int missing(char *dirname) {/*{{{*/
642 return (!S_ISDIR(buf.st_mode));
645 int init(int fullscreen) {/*{{{*/
652 read_high_score_table();
654 // Where are our data files?
656 // second alternative: RD_DATADIR
657 // final alternative: /usr/share/vor
658 data_dir = strdup("./data");
659 if (missing(data_dir)) {
661 env = getenv("RD_DATADIR");
663 data_dir = strdup(env);
664 if (missing(data_dir)) {
665 fprintf (stderr,"Cannot find data directory $RD_DATADIR\n");
670 data_dir = strdup("/usr/share/vor");
671 if (missing(data_dir)) {
672 fprintf (stderr,"Cannot find data in %s\n", data_dir);
678 if (oss_sound_flag) {
680 // Initialise SDL with audio and video
681 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)!=0) {
683 printf ("Can't open sound, starting without it\n");
688 atexit(SDL_CloseAudio);
689 oss_sound_flag = init_sound();
694 // Initialise with video only
695 CONDERROR(SDL_Init(SDL_INIT_VIDEO)!=0);
702 // Attempt to get the required video size
703 flag = SDL_DOUBLEBUF | SDL_HWSURFACE;
704 if (fullscreen) flag |= SDL_FULLSCREEN;
705 surf_screen = SDL_SetVideoMode(XSIZE,YSIZE,16,flag);
707 // Set the title bar text
708 SDL_WM_SetCaption("Rock Dodgers", "rockdodgers");
710 NULLERROR(surf_screen);
712 // Set the heat color from the range 0 (cold) to 300 (blue-white)
713 for (i=0; i<W*3; i++)
714 heatcolor[i] = SDL_MapRGB(
716 (i<W)?(i*M/W):(M),(i<W)?0:(i<2*W)?((i-W)*M/W):M,(i<2*W)?0:((i-W)*M/W) // Got that?
720 NULLERROR(temp = IMG_Load(load_file("banners/variations.png")));
721 NULLERROR(surf_b_variations = SDL_DisplayFormat(temp));
723 NULLERROR(temp = IMG_Load(load_file("banners/on.png")));
724 NULLERROR(surf_b_on = SDL_DisplayFormat(temp));
726 NULLERROR(temp = IMG_Load(load_file("banners/rockdodger.png")));
727 NULLERROR(surf_b_rockdodger = SDL_DisplayFormat(temp));
729 NULLERROR(temp = IMG_Load(load_file("banners/game.png")));
730 NULLERROR(surf_b_game = SDL_DisplayFormat(temp));
732 NULLERROR(temp = IMG_Load(load_file("banners/over.png")));
733 NULLERROR(surf_b_over = SDL_DisplayFormat(temp));
735 surf_font_big = IMG_Load(load_file(BIG_FONT_FILE));
736 InitFont(surf_font_big);
738 // Load the spaceship graphic.
739 NULLERROR(temp = IMG_Load(load_file("sprites/ship.png")));
740 NULLERROR(surf_ship = SDL_DisplayFormat(temp));
742 // Load the life indicator (small ship) graphic.
743 NULLERROR(temp = IMG_Load(load_file("indicators/life.png")));
744 NULLERROR(surf_life = SDL_DisplayFormat(temp));
746 // Create the array of black points;
747 SDL_LockSurface(surf_ship);
748 raw_pixels = (Uint16 *) surf_ship->pixels;
749 for (i=0; i<surf_ship->w; i++)
750 for (j=0; j<surf_ship->h; j++)
751 if (raw_pixels[j*(surf_ship->pitch)/2+i] == 0) {
756 SDL_UnlockSurface(surf_ship);
761 // Load all our lovely rocks
762 for (i=0; i<NROCKS; i++) {
765 sprintf(a,load_file("sprites/rock%d.png"),i);
766 NULLERROR(temp = IMG_Load(a));
767 NULLERROR(surf_rock[i] = SDL_DisplayFormat(temp));
769 sprintf(a,load_file("sprites/deadrock%d.png"),i);
770 NULLERROR(temp = IMG_Load(a));
771 NULLERROR(surf_deadrock[i] = SDL_DisplayFormat(temp));
774 // Remove the mouse cursor
776 SDL_ShowCursor(SDL_DISABLE);
784 struct black_point_struct *p;
788 float fadegame,fadeover;
790 char *statedisplay, buf[1024];
799 // Draw a fully black background
800 SDL_FillRect(surf_screen,NULL,0);
805 // Show the current state
808 statedisplay = "title_page";
811 statedisplay = "gameplay";
814 statedisplay = "dead_pause";
817 statedisplay = "game_over";
819 case HIGH_SCORE_ENTRY:
820 statedisplay = "high_score_entry";
822 case HIGH_SCORE_DISPLAY:
823 statedisplay = "high_score_display";
826 statedisplay = "demo";
829 snprintf(buf,1024, "mode=%s", statedisplay);
830 PutString(surf_screen,0,YSIZE-50,buf);
834 // Draw the background dots
835 drawdots(surf_screen);
837 // If it's firing, draw the laser
842 if (!gameover && (state==GAMEPLAY || state==DEMO) ) {
843 src.w = surf_ship->w;
844 src.h = surf_ship->h;
849 SDL_BlitSurface(surf_ship,&src,surf_screen,&dest);
852 // Draw all the rocks, in all states
853 for (i=0; i<MAXROCKS; i++) {
854 if (rock[i].active) {
856 src.w = rock[i].image->w;
857 src.h = rock[i].image->h;
860 dest.x = (int) rock[i].x;
861 dest.y = (int) rock[i].y;
864 SDL_BlitSurface(rock[i].image,&src,surf_screen,&dest);
866 // Draw the heated part of the rock, in an alpha which reflects the
867 // amount of heat in the rock.
868 if (rock[i].heat>0) {
869 SDL_Surface *deadrock;
870 deadrock = surf_deadrock[rock[i].type_number];
871 SDL_SetAlpha(deadrock,SDL_SRCALPHA,rock[i].heat*255/rock[i].image->h);
872 dest.x = (int) rock[i].x; // kludge
873 SDL_BlitSurface(deadrock,&src,surf_screen,&dest);
874 if (rnd()<0.3) rock[i].heat-=movementrate;
877 // If the rock is heated past a certain point, the water content of
878 // the rock flashes to steam, releasing enough energy to destroy
879 // the rock in spectacular fashion.
880 if (rock[i].heat>rock[i].image->h) {
882 play_sound(1+(int)(rnd()*3));
883 makebangdots(rock[i].x,rock[i].y,rock[i].xvel,rock[i].yvel,rock[i].image,10);
889 // If it's game over, show the game over graphic in the dead centre
894 if (fadetimer<3.0/faderate)
895 fadegame=fadetimer/(3.0/faderate);
899 if (fadetimer<3.0/faderate)
902 if (fadetimer<6.0/faderate)
903 fadeover = ((3.0/faderate)-fadetimer)/(6.0/faderate);
907 src.w = surf_b_game->w;
908 src.h = surf_b_game->h;
911 dest.x = (XSIZE-src.w)/2;
912 dest.y = (YSIZE-src.h)/2-40;
913 SDL_SetAlpha(surf_b_game, SDL_SRCALPHA, (int)(fadegame*(200+55*cos(fadetimer+=movementrate/1.0))));
914 SDL_BlitSurface(surf_b_game,&src,surf_screen,&dest);
916 src.w = surf_b_over->w;
917 src.h = surf_b_over->h;
920 dest.x = (XSIZE-src.w)/2;
921 dest.y = (YSIZE-src.h)/2+40;
922 SDL_SetAlpha(surf_b_over, SDL_SRCALPHA, (int)(fadeover*(200+55*sin(fadetimer))));
923 SDL_BlitSurface(surf_b_over,&src,surf_screen,&dest);
927 src.w = surf_b_variations->w;
928 src.h = surf_b_variations->h;
931 dest.x = (XSIZE-src.w)/2 + cos(fadetimer/6.5)*10;
932 dest.y = (YSIZE/2-src.h)/2 + sin(fadetimer/5.0)*10;
933 SDL_SetAlpha(surf_b_variations, SDL_SRCALPHA, (int)(200+55*sin(fadetimer+=movementrate/2.0)));
934 SDL_BlitSurface(surf_b_variations,&src,surf_screen,&dest);
936 src.w = surf_b_on->w;
937 src.h = surf_b_on->h;
940 dest.x = (XSIZE-src.w)/2 + cos((fadetimer+1.0)/6.5)*10;
941 dest.y = (YSIZE/2-src.h)/2 + surf_b_variations->h + 20 + sin((fadetimer+1.0)/5.0)*10;
942 SDL_SetAlpha(surf_b_on, SDL_SRCALPHA, (int)(200+55*sin(fadetimer-1.0)));
943 SDL_BlitSurface(surf_b_on,&src,surf_screen,&dest);
945 src.w = surf_b_rockdodger->w;
946 src.h = surf_b_rockdodger->h;
949 dest.x = (XSIZE-src.w)/2 + cos((fadetimer+2.0)/6.5)*10;
950 dest.y = (YSIZE/2-src.h)/2 + surf_b_variations->h + surf_b_on->h + 40 + sin((fadetimer+2.0)/5)*10;
951 SDL_SetAlpha(surf_b_rockdodger, SDL_SRCALPHA, (int)(200+55*sin(fadetimer-2.0)));
952 SDL_BlitSurface(surf_b_rockdodger,&src,surf_screen,&dest);
954 text = "Version " VERSION;
955 x = (XSIZE-SFont_wide(text))/2 + sin(fadetimer/4.5)*10;
956 PutString(surf_screen,x,YSIZE-50+sin(fadetimer/2)*5,text);
958 text = sequence[(int)(fadetimer/40)%NSEQUENCE];
959 //text = "Press SPACE to start!";
960 x = (XSIZE-SFont_wide(text))/2 + cos(fadetimer/4.5)*10;
961 PutString(surf_screen,x,YSIZE-100+cos(fadetimer/3)*5,text);
964 case HIGH_SCORE_ENTRY:
966 if (score >= high[7].score) {
968 if (SFont_Input (surf_screen, 330, 50+(scorerank+2)*font_height, 300, name)) {
969 // Insert name into high score table
971 // Lose the lowest name forever (loser!)
972 //if (high[7].allocated)
973 // free(high[7].name); // THIS WAS CRASHING SO I REMOVED IT
975 // Insert new high score
976 high[scorerank].score = score;
977 high[scorerank].name = strdup(name); // MEMORY NEVER FREED!
978 high[scorerank].allocated = 1;
980 // Set the global name string to "", ready for the next winner
983 // Change state to briefly show high scores page
984 state = HIGH_SCORE_DISPLAY;
987 // Write the high score table to the file
988 write_high_score_table();
990 // Play the title page tune
995 state = HIGH_SCORE_DISPLAY;
999 case HIGH_SCORE_DISPLAY:
1000 // Display de list o high scores mon.
1001 PutString(surf_screen,180,50,"High scores");
1002 for (i=0; i<8; i++) {
1004 sprintf(s, "#%1d",i+1);
1005 PutString(surf_screen, 150, 50+(i+2)*font_height,s);
1006 snprintscore(s, 1024, high[i].score);
1007 PutString(surf_screen, 200, 50+(i+2)*font_height,s);
1008 sprintf(s, "%3s", high[i].name);
1009 PutString(surf_screen, 330, 50+(i+2)*font_height,s);
1014 if (!gameover && state==GAMEPLAY) {
1015 // Show the freaky shields
1016 SDL_LockSurface(surf_screen);
1017 raw_pixels = (Uint16 *) surf_screen->pixels;
1018 if (initialshield>0 || shieldsup && shieldlevel>0) {
1022 if (initialshield>0) {
1023 initialshield-=movementrate;
1024 c = SDL_MapRGB(surf_screen->format,0,255,255);
1027 c = heatcolor[(int)shieldlevel];
1028 shieldlevel-=movementrate;
1032 for (p=black_point; p<blackptr; p++) {
1033 x = p->x + (int)xship + (rnd()+rnd()-1)*sin(shieldpulse)*4 + 1;
1034 y = p->y + (int)yship + (rnd()+rnd()-1)*sin(shieldpulse)*4 + 1;
1035 if (x>0 && y>0 && x<XSIZE && y<YSIZE) {
1036 offset = surf_screen->pitch/2 * y + x;
1037 raw_pixels[offset] = c;
1042 // When the shields are off, check that the black points
1043 // on the ship are still black, and not covered up by rocks
1044 for (p=black_point; p<blackptr; p++) {
1045 offset = surf_screen->pitch/2 * (p->y + (int)yship) + p->x + (int)xship;
1046 if (raw_pixels[offset]) {
1047 // Set the bang flag
1052 SDL_UnlockSurface(surf_screen);
1056 dotcollision(surf_screen); // Kill dots that are not on their spots
1059 // Draw all the little ships
1060 if (state==GAMEPLAY || state==DEAD_PAUSE || state==GAME_OVER)
1061 for (i=0; i<nships-1; i++) {
1062 src.w = surf_life->w;
1063 src.h = surf_life->h;
1066 dest.x = (i+1)*(src.w+10);
1068 SDL_BlitSurface(surf_life,&src,surf_screen,&dest);
1074 n=SDL_GetTicks()-initticks;
1076 ticks_since_last = n-score;
1080 ticks_since_last = SDL_GetTicks()-last_ticks;
1081 last_ticks = SDL_GetTicks();
1082 if (ticks_since_last>200 || ticks_since_last<0) {
1086 movementrate = ticks_since_last/50.0;
1087 if (state==GAMEPLAY)
1088 score += ticks_since_last;
1091 // Update the surface
1092 SDL_Flip(surf_screen);
1097 int gameloop() {/*{{{*/
1105 // Count down the game loop timer, and change state when it gets to zero or less;
1107 if ((state_timeout -= movementrate*3) < 0) {
1110 // Create a new ship and start all over again
1113 initialshield = 150;
1121 state = HIGH_SCORE_ENTRY;
1124 state_timeout=5.0e6;
1126 if (score>=high[7].score) {
1127 // Read the high score table from the storage file
1128 read_high_score_table();
1130 // Find ranking of this score, store as scorerank
1131 for (i=0; i<8; i++) {
1132 if (high[i].score <= score) {
1138 // Move all lower scores down a notch
1139 for (i=7; i>=scorerank; i--)
1140 high[i] = high[i-1];
1142 // Insert blank high score
1143 high[scorerank].score = score;
1144 high[scorerank].name = "";
1145 high[scorerank].allocated = 0;
1149 case HIGH_SCORE_DISPLAY:
1151 state_timeout=500.0;
1153 case HIGH_SCORE_ENTRY:
1154 // state = TITLE_PAGE;
1156 // state_timeout=100.0;
1161 state_timeout=100.0;
1164 state = HIGH_SCORE_DISPLAY;
1165 state_timeout=100.0;
1169 state = HIGH_SCORE_DISPLAY;
1170 state_timeout=200.0;
1176 if (--countdown<=0 && (rnd()*100.0<(rockrate+=0.025))) {
1179 if (rockptr-rock>=MAXROCKS)
1181 if (!rockptr->active) {
1182 rockptr->x = (float)XSIZE;
1183 rockptr->xvel = -(rockspeed)*(1+rnd());
1184 rockptr->yvel = rnd()-0.5;
1185 rockptr->type_number = random() % NROCKS;
1187 rockptr->image = surf_rock[rockptr->type_number];// [random()%NROCKS];
1188 rockptr->active = 1;
1189 rockptr->y = rnd()*(YSIZE + rockptr->image->h);
1191 if (movementrate>0.1)
1192 countdown = (int)(ROCKRATE/movementrate);
1199 xvel *= pow((double)0.9,(double)movementrate);
1200 yvel *= pow((double)0.9,(double)movementrate);
1201 // if (abs(xvel)<0.00001) xvel=0;
1202 // if (abs(yvel)<0.00001) yvel=0;
1206 xship += xvel*movementrate;
1207 yship += yvel*movementrate;
1210 yscroll = yship - (YSIZE / 2);
1212 yscroll = yscroll*movementrate;
1215 // Move all the rocks
1216 for (i=0; i<MAXROCKS; i++) if (rock[i].active) {
1217 rock[i].x += rock[i].xvel*movementrate;
1218 rock[i].y += rock[i].yvel*movementrate + yscroll;
1219 if(rock[i].y > YSIZE) {
1221 rock[i].y -= rock[i].image->w;
1222 } else if(rock[i].y < -rock[i].image->w) {
1224 rock[i].y += rock[i].image->w;
1226 if (rock[i].x<-32.0)
1232 if (xship<0 || xship>XSIZE-surf_ship->w) {
1233 // BOUNCE from left and right wall
1234 xship -= xvel*movementrate;
1239 if (yship<0 || yship>YSIZE-surf_ship->h) {
1240 // BOUNCE from top and bottom wall
1246 if (draw() && state==GAMEPLAY) {
1247 if (oss_sound_flag) {
1248 // Play the explosion sound
1251 makebangdots(xship,yship,xvel,yvel,surf_ship,30);
1255 state_timeout = 200.0;
1257 faderate=movementrate;
1261 state_timeout = 100.0;
1266 keystate = SDL_GetKeyState(NULL);
1268 if (state!=HIGH_SCORE_ENTRY && (keystate[SDLK_q] || keystate[SDLK_ESCAPE]))
1271 if (keystate[SDLK_SPACE] && (state==HIGH_SCORE_DISPLAY || state==TITLE_PAGE || state==DEMO)) {
1273 for (i=0; i<MAXROCKS; i++) rock[i].active=0;
1299 keystate = SDL_GetKeyState(NULL);
1302 if (state==GAMEPLAY) {
1306 if (keystate[SDLK_UP]) { yvel -= 1.5*movementrate; maneuver|=1<<3;}
1307 if (keystate[SDLK_DOWN]) { yvel += 1.5*movementrate; maneuver|=1<<1;}
1308 if (keystate[SDLK_LEFT]) { xvel -= 1.5*movementrate; maneuver|=1<<2;}
1309 if (keystate[SDLK_RIGHT]) { xvel += 1.5*movementrate; maneuver|=1;}
1310 if (keystate[SDLK_d]) { laser=1; }
1311 if (keystate[SDLK_1]) { fast=1; }
1312 if (keystate[SDLK_2]) { fast=0; }
1313 if (keystate[SDLK_3]) { SDL_SaveBMP(surf_screen, "snapshot.bmp"); }
1314 shieldsup = keystate[SDLK_s];
1317 if (keystate[SDLK_p]) {
1322 src.w = surf_b_variations->w;
1323 src.h = surf_b_variations->h;
1326 dest.x = (XSIZE-src.w)/2;
1327 dest.y = (YSIZE-src.h)/2;
1328 SDL_BlitSurface(surf_b_variations,&src,surf_screen,&dest);
1329 // Update the surface
1330 SDL_Flip(surf_screen);
1334 printf ("not paused\n");
1351 // DEBUG mode to slow down the action, and see if this game is playable on a 486
1356 main(int argc, char **argv) {/*{{{*/
1357 int i, x, fullscreen;
1364 while ((x=getopt(argc,argv,"efhsp"))>=0)
1369 case 'f': // fullscreen
1373 printf ("Rock Dodgers\n"
1374 " -e Big tail [E]ngine\n"
1375 " -f [F]ull screen\n"
1376 " -h This [H]elp message\n"
1377 " -p Stupid original [P]hysics (friction)\n"
1378 " -s [S]ilent (no sound)\n");
1381 case 'p': // physics
1389 if (init(fullscreen)) {
1390 printf ("ta: '%s'\n",initerror);
1395 for (i=0; i<MAXROCKS; i++)
1399 initticks = SDL_GetTicks();
1400 if (gameloop()==0) break;
1401 printf ("score=%d\n",score);