2 Space Rocks! Avoid the rocks as long as you can! {{{
3 Copyright (C) 2001 Paul Holt <pad@pcholt.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 extern int font_height;
27 #include <SDL/SDL_image.h>
34 #include <sys/types.h>
43 #define NROCKS 6 // Number of rock image files, not number of rocks visible
44 #define MAXROCKS 120 // MAX Rocks
45 #define MAXROCKHEIGHT 100
47 #define MAXBLACKPOINTS 500
48 #define MAXENGINEDOTS 5000
49 #define MAXBANGDOTS 50000
50 #define MAXSPACEDOTS 2000
53 #define BIG_FONT_FILE "fonts/score.png"
56 #define CONDERROR(a) if ((a)) {initerror=strdup(SDL_GetError());return 1;}
57 #define NULLERROR(a) CONDERROR((a)==NULL)
60 // ************************************* STRUCTS
61 struct rock_struct {/*{{{*/
62 // Array of black pixel coordinates. This is scanned
63 // every frame to see if it's still black, and as
64 // soon as it isn't we BLOW UP
71 struct black_point_struct {/*{{{*/
74 struct bangdots {/*{{{*/
75 // Bang dots have the same colour as shield dots.
76 // Bang dots get darker as they age.
77 // Some are coloured the same as the ex-ship.
79 Uint16 c; // when zero, use heatcolor[bangdotlife]
80 float life; // When reduced to 0, set active=0
82 float decay;// Amount by which to reduce life each time dot is drawn
84 struct enginedots {/*{{{*/
85 // Engine dots stream out the back of the ship, getting darker as they go.
88 // The life of an engine dot
89 // is a number starting at between 0 and 50 and counting backward.
90 float life; // When reduced to 0, set active=0
92 struct spacedot {/*{{{*/
93 // Space dots are harmless background items
94 // All are active. When one falls off the edge, another is created at the start.
98 // High score table {{{
115 // ************************************* VARS
116 // SDL_Surface global variables {{{
118 *surf_screen, // Screen
119 *surf_b_rock, // Title element "rock"
120 *surf_b_dodgers, // Title element "dodgers"
121 *surf_b_game, // Title element "game"
122 *surf_b_over, // Title element "over"
123 *surf_ship, // Spaceship element
124 *surf_life, // Indicator of number of ships remaining
125 *surf_rock[NROCKS], // THE ROCKS
126 *surf_deadrock[NROCKS], // THE DEAD ROCKS
127 *surf_font_big; // The big font
129 // Structure global variables {{{
130 struct enginedots edot[MAXENGINEDOTS], *dotptr=edot;
131 struct rock_struct rock[MAXROCKS], *rockptr=rock;
132 struct black_point_struct black_point[MAXBLACKPOINTS], *blackptr=black_point;
133 struct bangdots bdot[MAXBANGDOTS], *bdotptr=bdot;
134 struct spacedot sdot[MAXSPACEDOTS];
136 // Other global variables {{{
138 char *initerror = "";
139 char name[1024], debug1[1024];
141 float xship,yship = 240.0; // X position, 0..XSIZE
142 float xvel,yvel; // Change in X position per tick.
143 float rockrate,rockspeed;
145 float shieldlevel, shieldpulse=0;
148 int nships,score,initticks,ticks_since_last, last_ticks;
149 int initialshield, gameover, fast;
154 int oss_sound_flag=0;
155 int tail_plume=0; // display big engine at the back?
156 int friction=0; // should there be friction?
158 float fadetimer=0,faderate;
160 int pausedown=0,paused=0;
162 // bangdot start (bd1) and end (bd2) position:
165 int xoffset[NROCKS][MAXROCKHEIGHT];
176 enum states state=TITLE_PAGE;
177 float state_timeout = 600.0;
179 const int fakesin[] = {0,1,0,-1};
180 const int fakecos[] = {1,0,-1,0};
183 "Press SPACE to start",
184 "http://spacerocks.sourceforge.net",
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/rockdodger/.highscore",mode)) {
236 sprintf(s,"%s/.rockdodger_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/rockdodger
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/rockdodger");
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/rock.png")));
721 NULLERROR(surf_b_rock = SDL_DisplayFormat(temp));
723 NULLERROR(temp = IMG_Load(load_file("banners/dodgers.png")));
724 NULLERROR(surf_b_dodgers = SDL_DisplayFormat(temp));
726 NULLERROR(temp = IMG_Load(load_file("banners/game.png")));
727 NULLERROR(surf_b_game = SDL_DisplayFormat(temp));
729 NULLERROR(temp = IMG_Load(load_file("banners/over.png")));
730 NULLERROR(surf_b_over = SDL_DisplayFormat(temp));
732 surf_font_big = IMG_Load(load_file(BIG_FONT_FILE));
733 InitFont(surf_font_big);
735 // Load the spaceship graphic.
736 NULLERROR(temp = IMG_Load(load_file("sprites/ship.png")));
737 NULLERROR(surf_ship = SDL_DisplayFormat(temp));
739 // Load the life indicator (small ship) graphic.
740 NULLERROR(temp = IMG_Load(load_file("indicators/life.png")));
741 NULLERROR(surf_life = SDL_DisplayFormat(temp));
743 // Create the array of black points;
744 SDL_LockSurface(surf_ship);
745 raw_pixels = (Uint16 *) surf_ship->pixels;
746 for (i=0; i<surf_ship->w; i++)
747 for (j=0; j<surf_ship->h; j++)
748 if (raw_pixels[j*(surf_ship->pitch)/2+i] == 0) {
753 SDL_UnlockSurface(surf_ship);
758 // Load all our lovely rocks
759 for (i=0; i<NROCKS; i++) {
762 sprintf(a,load_file("sprites/rock%d.png"),i);
763 NULLERROR(temp = IMG_Load(a));
764 NULLERROR(surf_rock[i] = SDL_DisplayFormat(temp));
766 sprintf(a,load_file("sprites/deadrock%d.png"),i);
767 NULLERROR(temp = IMG_Load(a));
768 NULLERROR(surf_deadrock[i] = SDL_DisplayFormat(temp));
771 // Remove the mouse cursor
773 SDL_ShowCursor(SDL_DISABLE);
781 struct black_point_struct *p;
785 float fadegame,fadeover;
787 char *statedisplay, buf[1024];
796 // Draw a fully black background
797 SDL_FillRect(surf_screen,NULL,0);
802 // Show the current state
805 statedisplay = "title_page";
808 statedisplay = "gameplay";
811 statedisplay = "dead_pause";
814 statedisplay = "game_over";
816 case HIGH_SCORE_ENTRY:
817 statedisplay = "high_score_entry";
819 case HIGH_SCORE_DISPLAY:
820 statedisplay = "high_score_display";
823 statedisplay = "demo";
826 snprintf(buf,1024, "mode=%s", statedisplay);
827 PutString(surf_screen,0,YSIZE-50,buf);
831 // Draw the background dots
832 drawdots(surf_screen);
834 // If it's firing, draw the laser
839 if (!gameover && (state==GAMEPLAY || state==DEMO) ) {
840 src.w = surf_ship->w;
841 src.h = surf_ship->h;
846 SDL_BlitSurface(surf_ship,&src,surf_screen,&dest);
849 // Draw all the rocks, in all states
850 for (i=0; i<MAXROCKS; i++) {
851 if (rock[i].active) {
853 src.w = rock[i].image->w;
854 src.h = rock[i].image->h;
857 dest.x = (int) rock[i].x;
858 dest.y = (int) rock[i].y;
861 SDL_BlitSurface(rock[i].image,&src,surf_screen,&dest);
863 // Draw the heated part of the rock, in an alpha which reflects the
864 // amount of heat in the rock.
865 if (rock[i].heat>0) {
866 SDL_Surface *deadrock;
867 deadrock = surf_deadrock[rock[i].type_number];
868 SDL_SetAlpha(deadrock,SDL_SRCALPHA,rock[i].heat*255/rock[i].image->h);
869 dest.x = (int) rock[i].x; // kludge
870 SDL_BlitSurface(deadrock,&src,surf_screen,&dest);
871 if (rnd()<0.3) rock[i].heat-=movementrate;
874 // If the rock is heated past a certain point, the water content of
875 // the rock flashes to steam, releasing enough energy to destroy
876 // the rock in spectacular fashion.
877 if (rock[i].heat>rock[i].image->h) {
879 play_sound(1+(int)(rnd()*3));
880 makebangdots(rock[i].x,rock[i].y,rock[i].xvel,rock[i].yvel,rock[i].image,10);
886 // If it's game over, show the game over graphic in the dead centre
891 if (fadetimer<3.0/faderate)
892 fadegame=fadetimer/(3.0/faderate);
896 if (fadetimer<3.0/faderate)
899 if (fadetimer<6.0/faderate)
900 fadeover = ((3.0/faderate)-fadetimer)/(6.0/faderate);
904 src.w = surf_b_game->w;
905 src.h = surf_b_game->h;
908 dest.x = (XSIZE-src.w)/2;
909 dest.y = (YSIZE-src.h)/2-40;
910 SDL_SetAlpha(surf_b_game, SDL_SRCALPHA, (int)(fadegame*(200+55*cos(fadetimer+=movementrate/1.0))));
911 SDL_BlitSurface(surf_b_game,&src,surf_screen,&dest);
913 src.w = surf_b_over->w;
914 src.h = surf_b_over->h;
917 dest.x = (XSIZE-src.w)/2;
918 dest.y = (YSIZE-src.h)/2+40;
919 SDL_SetAlpha(surf_b_over, SDL_SRCALPHA, (int)(fadeover*(200+55*sin(fadetimer))));
920 SDL_BlitSurface(surf_b_over,&src,surf_screen,&dest);
924 src.w = surf_b_rock->w;
925 src.h = surf_b_rock->h;
928 dest.x = (XSIZE-src.w)/2 + cos(fadetimer/6.5)*10;
929 dest.y = (YSIZE/2-src.h)/2 + sin(fadetimer/5)*10;
930 SDL_SetAlpha(surf_b_rock, SDL_SRCALPHA, (int)(200+55*sin(fadetimer+=movementrate/2.0)));
931 SDL_BlitSurface(surf_b_rock,&src,surf_screen,&dest);
932 src.w = surf_b_dodgers->w;
933 src.h = surf_b_dodgers->h;
936 dest.x = (XSIZE-src.w)/2+sin(fadetimer/6.5)*10;
937 dest.y = (YSIZE/2-src.h)/2 + surf_b_rock->h + 20 + sin((fadetimer+1)/5)*10;
938 SDL_SetAlpha(surf_b_dodgers, SDL_SRCALPHA, (int)(200+55*sin(fadetimer-1.0)));
939 SDL_BlitSurface(surf_b_dodgers,&src,surf_screen,&dest);
941 text = "Version " VERSION;
942 x = (XSIZE-SFont_wide(text))/2 + sin(fadetimer/4.5)*10;
943 PutString(surf_screen,x,YSIZE-50+sin(fadetimer/2)*5,text);
945 text = sequence[(int)(fadetimer/40)%NSEQUENCE];
946 //text = "Press SPACE to start!";
947 x = (XSIZE-SFont_wide(text))/2 + cos(fadetimer/4.5)*10;
948 PutString(surf_screen,x,YSIZE-100+cos(fadetimer/3)*5,text);
951 case HIGH_SCORE_ENTRY:
953 if (score >= high[7].score) {
955 if (SFont_Input (surf_screen, 330, 50+(scorerank+2)*font_height, 300, name)) {
956 // Insert name into high score table
958 // Lose the lowest name forever (loser!)
959 //if (high[7].allocated)
960 // free(high[7].name); // THIS WAS CRASHING SO I REMOVED IT
962 // Insert new high score
963 high[scorerank].score = score;
964 high[scorerank].name = strdup(name); // MEMORY NEVER FREED!
965 high[scorerank].allocated = 1;
967 // Set the global name string to "", ready for the next winner
970 // Change state to briefly show high scores page
971 state = HIGH_SCORE_DISPLAY;
974 // Write the high score table to the file
975 write_high_score_table();
977 // Play the title page tune
982 state = HIGH_SCORE_DISPLAY;
986 case HIGH_SCORE_DISPLAY:
987 // Display de list o high scores mon.
988 PutString(surf_screen,180,50,"High scores");
989 for (i=0; i<8; i++) {
991 sprintf(s, "#%1d",i+1);
992 PutString(surf_screen, 150, 50+(i+2)*font_height,s);
993 snprintscore(s, 1024, high[i].score);
994 PutString(surf_screen, 200, 50+(i+2)*font_height,s);
995 sprintf(s, "%3s", high[i].name);
996 PutString(surf_screen, 330, 50+(i+2)*font_height,s);
1001 if (!gameover && state==GAMEPLAY) {
1002 // Show the freaky shields
1003 SDL_LockSurface(surf_screen);
1004 raw_pixels = (Uint16 *) surf_screen->pixels;
1005 if (initialshield>0 || shieldsup && shieldlevel>0) {
1009 if (initialshield>0) {
1010 initialshield-=movementrate;
1011 c = SDL_MapRGB(surf_screen->format,0,255,255);
1014 c = heatcolor[(int)shieldlevel];
1015 shieldlevel-=movementrate;
1019 for (p=black_point; p<blackptr; p++) {
1020 x = p->x + (int)xship + (rnd()+rnd()-1)*sin(shieldpulse)*4 + 1;
1021 y = p->y + (int)yship + (rnd()+rnd()-1)*sin(shieldpulse)*4 + 1;
1022 if (x>0 && y>0 && x<XSIZE && y<YSIZE) {
1023 offset = surf_screen->pitch/2 * y + x;
1024 raw_pixels[offset] = c;
1029 // When the shields are off, check that the black points
1030 // on the ship are still black, and not covered up by rocks
1031 for (p=black_point; p<blackptr; p++) {
1032 offset = surf_screen->pitch/2 * (p->y + (int)yship) + p->x + (int)xship;
1033 if (raw_pixels[offset]) {
1034 // Set the bang flag
1039 SDL_UnlockSurface(surf_screen);
1043 dotcollision(surf_screen); // Kill dots that are not on their spots
1046 // Draw all the little ships
1047 if (state==GAMEPLAY || state==DEAD_PAUSE || state==GAME_OVER)
1048 for (i=0; i<nships-1; i++) {
1049 src.w = surf_life->w;
1050 src.h = surf_life->h;
1053 dest.x = (i+1)*(src.w+10);
1055 SDL_BlitSurface(surf_life,&src,surf_screen,&dest);
1061 n=SDL_GetTicks()-initticks;
1063 ticks_since_last = n-score;
1067 ticks_since_last = SDL_GetTicks()-last_ticks;
1068 last_ticks = SDL_GetTicks();
1069 if (ticks_since_last>200 || ticks_since_last<0) {
1073 movementrate = ticks_since_last/50.0;
1074 if (state==GAMEPLAY)
1075 score += ticks_since_last;
1078 // Update the surface
1079 SDL_Flip(surf_screen);
1084 int gameloop() {/*{{{*/
1092 // Count down the game loop timer, and change state when it gets to zero or less;
1094 if ((state_timeout -= movementrate*3) < 0) {
1097 // Create a new ship and start all over again
1100 initialshield = 150;
1108 state = HIGH_SCORE_ENTRY;
1111 state_timeout=5.0e6;
1113 if (score>=high[7].score) {
1114 // Read the high score table from the storage file
1115 read_high_score_table();
1117 // Find ranking of this score, store as scorerank
1118 for (i=0; i<8; i++) {
1119 if (high[i].score <= score) {
1125 // Move all lower scores down a notch
1126 for (i=7; i>=scorerank; i--)
1127 high[i] = high[i-1];
1129 // Insert blank high score
1130 high[scorerank].score = score;
1131 high[scorerank].name = "";
1132 high[scorerank].allocated = 0;
1136 case HIGH_SCORE_DISPLAY:
1138 state_timeout=500.0;
1140 case HIGH_SCORE_ENTRY:
1141 // state = TITLE_PAGE;
1143 // state_timeout=100.0;
1148 state_timeout=100.0;
1151 state = HIGH_SCORE_DISPLAY;
1152 state_timeout=100.0;
1156 state = HIGH_SCORE_DISPLAY;
1157 state_timeout=200.0;
1163 if (--countdown<=0 && (rnd()*100.0<(rockrate+=0.025))) {
1166 if (rockptr-rock>=MAXROCKS)
1168 if (!rockptr->active) {
1169 rockptr->x = (float)XSIZE;
1170 rockptr->xvel = -(rockspeed)*(1+rnd());
1171 rockptr->yvel = rnd()-0.5;
1172 rockptr->type_number = random() % NROCKS;
1174 rockptr->image = surf_rock[rockptr->type_number];// [random()%NROCKS];
1175 rockptr->active = 1;
1176 rockptr->y = rnd()*(YSIZE + rockptr->image->h);
1178 if (movementrate>0.1)
1179 countdown = (int)(ROCKRATE/movementrate);
1186 xvel *= pow((double)0.9,(double)movementrate);
1187 yvel *= pow((double)0.9,(double)movementrate);
1188 // if (abs(xvel)<0.00001) xvel=0;
1189 // if (abs(yvel)<0.00001) yvel=0;
1193 xship += xvel*movementrate;
1194 yship += yvel*movementrate;
1197 yscroll = yship - (YSIZE / 2);
1199 yscroll = yscroll*movementrate;
1202 // Move all the rocks
1203 for (i=0; i<MAXROCKS; i++) if (rock[i].active) {
1204 rock[i].x += rock[i].xvel*movementrate;
1205 rock[i].y += rock[i].yvel*movementrate + yscroll;
1206 if(rock[i].y > YSIZE) {
1208 rock[i].y -= rock[i].image->w;
1209 } else if(rock[i].y < -rock[i].image->w) {
1211 rock[i].y += rock[i].image->w;
1213 if (rock[i].x<-32.0)
1219 if (xship<0 || xship>XSIZE-surf_ship->w) {
1220 // BOUNCE from left and right wall
1221 xship -= xvel*movementrate;
1226 if (yship<0 || yship>YSIZE-surf_ship->h) {
1227 // BOUNCE from top and bottom wall
1233 if (draw() && state==GAMEPLAY) {
1234 if (oss_sound_flag) {
1235 // Play the explosion sound
1238 makebangdots(xship,yship,xvel,yvel,surf_ship,30);
1242 state_timeout = 200.0;
1244 faderate=movementrate;
1248 state_timeout = 100.0;
1253 keystate = SDL_GetKeyState(NULL);
1255 if (state!=HIGH_SCORE_ENTRY && (keystate[SDLK_q] || keystate[SDLK_ESCAPE]))
1258 if (keystate[SDLK_SPACE] && (state==HIGH_SCORE_DISPLAY || state==TITLE_PAGE || state==DEMO)) {
1260 for (i=0; i<MAXROCKS; i++) rock[i].active=0;
1286 keystate = SDL_GetKeyState(NULL);
1289 if (state==GAMEPLAY) {
1293 if (keystate[SDLK_UP]) { yvel -= 1.5*movementrate; maneuver|=1<<3;}
1294 if (keystate[SDLK_DOWN]) { yvel += 1.5*movementrate; maneuver|=1<<1;}
1295 if (keystate[SDLK_LEFT]) { xvel -= 1.5*movementrate; maneuver|=1<<2;}
1296 if (keystate[SDLK_RIGHT]) { xvel += 1.5*movementrate; maneuver|=1;}
1297 if (keystate[SDLK_d]) { laser=1; }
1298 if (keystate[SDLK_1]) { fast=1; }
1299 if (keystate[SDLK_2]) { fast=0; }
1300 if (keystate[SDLK_3]) { SDL_SaveBMP(surf_screen, "snapshot.bmp"); }
1301 shieldsup = keystate[SDLK_s];
1304 if (keystate[SDLK_p]) {
1309 src.w = surf_b_rock->w;
1310 src.h = surf_b_rock->h;
1313 dest.x = (XSIZE-src.w)/2;
1314 dest.y = (YSIZE-src.h)/2;
1315 SDL_BlitSurface(surf_b_rock,&src,surf_screen,&dest);
1316 // Update the surface
1317 SDL_Flip(surf_screen);
1321 printf ("not paused\n");
1338 // DEBUG mode to slow down the action, and see if this game is playable on a 486
1343 main(int argc, char **argv) {/*{{{*/
1344 int i, x, fullscreen;
1351 while ((x=getopt(argc,argv,"efhsp"))>=0)
1356 case 'f': // fullscreen
1360 printf ("Rock Dodgers\n"
1361 " -e Big tail [E]ngine\n"
1362 " -f [F]ull screen\n"
1363 " -h This [H]elp message\n"
1364 " -p Stupid original [P]hysics (friction)\n"
1365 " -s [S]ilent (no sound)\n");
1368 case 'p': // physics
1376 if (init(fullscreen)) {
1377 printf ("ta: '%s'\n",initerror);
1382 for (i=0; i<MAXROCKS; i++)
1386 initticks = SDL_GetTicks();
1387 if (gameloop()==0) break;
1388 printf ("score=%d\n",score);
1396 * $Id: main.c,v 1.22 2002/02/15 20:26:45 pad Exp $
1398 * Revision 1.22 2002/02/15 20:26:45 pad
1399 * Update - explosion time limits (ergh) and stuff
1401 * Revision 1.21 2002/01/26 14:13:27 pad
1402 * Released to pcholt.com as 0.4.0a
1404 * Revision 1.20 2002/01/20 22:24:41 pad
1405 * No longer crashes on space bar in high score table
1406 * Rocks make a random noise when they explode
1408 * Revision 1.19 2002/01/17 19:38:45 pad
1409 * Bang noise (must add more noises)
1411 * Revision 1.18 2002/01/16 01:34:28 pad
1412 * Rocks now change colour smoothly while being heated.
1414 * Revision 1.17 2002/01/15 21:56:51 pad
1415 * Lasers work, and rocks blow up, but unspectacularly.
1417 * Revision 1.16 2001/10/21 22:08:41 pad
1418 * Moving title screen,
1419 * New game-over graphics
1420 * High scores entered on the line of the new high score
1422 * Revision 1.15 2001/10/11 22:25:10 pad
1423 * High scores are saved!
1424 * /usr/share/rockdodger/.highscore or, if this is impossible,
1425 * $HOME/.rockdodger_high
1427 * Revision 1.14 2001/10/09 22:29:38 pad
1428 * Excellent! The game works, highscores are good, sound.c plays tunes,
1429 * the SFont.c has been revamped, and the game looks good to go.
1431 * Revision 1.13 2001/10/07 19:23:28 pad
1432 * SDL_mixer, music and sound added
1434 * Revision 1.12 2001/09/29 23:28:27 pad
1437 * Revision 1.11 2001/09/25 21:34:58 pad
1438 * Test for SDL_DISABLE
1439 * Something in sound.c I can't think what.
1441 * Revision 1.10 2001/09/21 21:37:06 pad
1442 * Donno. I canged something. Download it, it still works.
1443 * The laser doesn't do anything, but you can fire it by pressing "d".
1445 * Revision 1.9 2001/09/18 22:41:22 pad
1446 * The score stays on the screen no matter what the game mode.
1448 * Revision 1.7 2001/09/09 21:57:54 pad
1449 * Starting to add sound. There will be a background Ogg Vorbis soudtrack,
1450 * with a sample-driven sound effects engine.
1452 * Revision 1.6 2001/09/08 23:01:02 pad
1453 * Version number on start screen, from Makefile
1454 * Makefile 'make package' works
1456 * Revision 1.5 2001/09/08 00:13:03 pad
1459 * Revamped scoring system
1462 * Revision 1.4 2001/09/06 21:42:05 pad
1463 * Score is displayed using the lovely SFont library.
1465 * Revision 1.3 2001/09/03 22:50:34 pad
1466 * Functions cut back, larger number of space rocks.
1467 * Now it's an actual challenge.
1469 * Functions normalised - aim should be to have each function perform
1470 * one action and one action alone. This is not yet complete.
1472 * The high-speed movementrate error is fixed, but there are still
1473 * unexplained crashes. I must find out how to let SDL give me a core
1474 * dump to work with..