JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
04f65036e132e34331dc54b8324836915acd17d1
[vor.git] / main.c
1 /*
2     Space Rocks! Avoid the rocks as long as you can! {{{
3     Copyright (C) 2001  Paul Holt <pad@pcholt.com>
4
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.
9
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.
14
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
18     }}}
19 */
20 #undef DEBUG
21
22 extern int font_height;
23 void clearBuffer();
24
25 // includes {{{
26 #include <SDL/SDL.h>
27 #include <SDL/SDL_image.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <stdarg.h>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37
38 #include "SFont.h"
39 // }}}
40 // constants {{{
41 #define XSIZE 640
42 #define YSIZE 480
43 #define NROCKS 6    // Number of rock image files, not number of rocks visible
44 #define MAXROCKS 120 // MAX Rocks
45 #define MAXROCKHEIGHT 100
46 #define ROCKRATE 2
47 #define MAXBLACKPOINTS 500
48 #define MAXENGINEDOTS 5000
49 #define MAXBANGDOTS 50000
50 #define MAXSPACEDOTS 2000
51 #define W 100
52 #define M 255
53 #define BIG_FONT_FILE "fonts/score.png"
54 // }}}
55 // macros {{{
56 #define CONDERROR(a) if ((a)) {initerror=strdup(SDL_GetError());return 1;}
57 #define NULLERROR(a) CONDERROR((a)==NULL)
58 // }}}
59
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
65     float x,y,xvel,yvel;
66     int active;
67     SDL_Surface *image;
68     int type_number;
69     float heat;
70 }; /*}}}*/
71 struct black_point_struct {/*{{{*/
72     int x,y;
73 };/*}}}*/
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.
78     float x,y,dx,dy;
79     Uint16 c; // when zero, use heatcolor[bangdotlife]
80     float life; // When reduced to 0, set active=0
81     int active;
82     float decay;// Amount by which to reduce life each time dot is drawn
83 };/*}}}*/
84 struct enginedots {/*{{{*/
85     // Engine dots stream out the back of the ship, getting darker as they go.
86     int active;
87     float x,y,dx,dy;
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
91 };/*}}}*/
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.
95     float x,y,dx;
96     Uint16 color;
97 };/*}}}*/
98 // High score table {{{
99 struct highscore {
100     int score;
101     char *name;
102     int allocated;
103 } high[] = {
104     {13000,"Pad",0},
105     {12500,"Pad",0},
106     {6500,"Pad",0},
107     {5000,"Pad",0},
108     {3000,"Pad",0},
109     {2500,"Pad",0},
110     {2000,"Pad",0},
111     {1500,"Pad",0}
112 };
113 // }}}
114
115 // ************************************* VARS
116 // SDL_Surface global variables {{{
117 SDL_Surface 
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
128 // }}}
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];
135 // }}}
136 // Other global variables {{{
137 char topline[1024];
138 char *initerror = "";
139 char name[1024], debug1[1024];
140
141 float xship,yship = 240.0;      // X position, 0..XSIZE
142 float xvel,yvel;        // Change in X position per tick.
143 float rockrate,rockspeed;
144 float movementrate;
145 float shieldlevel, shieldpulse=0;
146 float yscroll;
147
148 int nships,score,initticks,ticks_since_last, last_ticks;
149 int initialshield, gameover, fast;
150 int countdown=0;
151 int maneuver = 0;
152 int laser = 0;
153 int shieldsup=0;
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?
157 int scorerank;
158 float fadetimer=0,faderate;
159
160 int pausedown=0,paused=0;
161
162 // bangdot start (bd1) and end (bd2) position:
163 int bd1=0, bd2=0;
164
165 int xoffset[NROCKS][MAXROCKHEIGHT];
166
167 enum states {/*{{{*/
168     TITLE_PAGE,
169     GAMEPLAY,
170     DEAD_PAUSE,
171     GAME_OVER,
172     HIGH_SCORE_ENTRY,
173     HIGH_SCORE_DISPLAY,
174     DEMO
175 };/*}}}*/
176 enum states state=TITLE_PAGE;
177 float state_timeout = 600.0;
178
179 const int fakesin[] = {0,1,0,-1};
180 const int fakecos[] = {1,0,-1,0};
181 #define NSEQUENCE 5
182 char *sequence[] = {
183     "Press SPACE to start",
184     "http://spacerocks.sourceforge.net",
185     "G'day tesmako",
186     "G'day overcode",
187     "S=shield D=laser"
188 };
189
190 int bangdotlife, nbangdots;
191 Uint16 heatcolor[W*3];
192
193 char *data_dir;
194 extern char *optarg;
195 extern int optind, opterr, optopt;
196 // }}}
197
198 // ************************************* FUNCS
199 #ifdef DOTCOLLISION
200 int dotcollision(SDL_Surface *s) {/*{{{*/
201     int i,j,m;
202     Uint16 *rawpixel, *r;
203
204     /*
205      * Kill all the dots which collide with other objects.
206      * This does not work, it's probably in the wrong place or something.
207      */
208     SDL_LockSurface(s);
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]))
215                     bdot[i].active=0;
216             }
217         }
218     }
219     SDL_UnlockSurface(s);
220
221     return;
222 }/*}}}*/
223 #endif
224
225 FILE *hs_fopen(char *mode) {/*{{{*/
226     FILE *f;
227     mode_t mask;
228     mask = umask(0111);
229     if (f=fopen("/usr/share/rockdodger/.highscore",mode)) {
230         umask(mask);
231         return f;
232     }
233     else {
234         char s[1024];
235         umask(0177);
236         sprintf(s,"%s/.rockdodger_high",getenv("HOME"));
237         if (f=fopen(s,mode)) {
238             umask(mask);
239             return f;
240         }
241         else {
242             umask(mask);
243             return 0;
244         }
245     }
246 }/*}}}*/
247 void read_high_score_table() {/*{{{*/
248     FILE *f;
249     int i;
250     if (f=hs_fopen("r")) {
251         // If the file exists, read from it
252         for (i=0; i<8; i++) {
253             char s[1024];
254             int highscore;
255             if (fscanf (f, "%d %[^\n]", &highscore, s)!=2)
256                 break;
257             if (high[i].allocated)
258                 free(high[i].name);
259             high[i].name = strdup(s);
260             high[i].score = highscore;
261             high[i].allocated = 1;
262         }
263         fclose(f);
264     }
265 }/*}}}*/
266 void write_high_score_table() {/*{{{*/
267     FILE *f;
268     int i;
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);
273         }
274         fclose(f);
275     }
276 }/*}}}*/
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;
281         if(min) {
282                 snprintf(s, n, "%2d:%.2d.%d", min, sec, tenths);
283         } else {
284                 snprintf(s, n, "   %2d.%d", sec, tenths);
285         }
286 }/*}}}*/
287 float rnd() {/*{{{*/
288     return (float)random()/(float)RAND_MAX;
289 }/*}}}*/
290 void init_engine_dots() {/*{{{*/
291     int i;
292     for (i=0; i<MAXENGINEDOTS; i++) {
293         edot[i].active=0;
294     }
295 }/*}}}*/
296 void init_space_dots() {/*{{{*/
297     int i,intensity;
298     for (i=0; i<MAXSPACEDOTS; i++) {
299         float r;
300
301         sdot[i].x = rnd()*(XSIZE-5);
302         sdot[i].y = rnd()*(YSIZE-5);
303
304         r = rnd()*rnd();
305
306         sdot[i].dx = -r*4;
307         // -1/((1-r)+.3);
308         intensity = (int)(r*180+70);
309         sdot[i].color = SDL_MapRGB(surf_screen->format,intensity,intensity,intensity);
310
311     }
312 }/*}}}*/
313
314 int drawlaser() {/*{{{*/
315     int i,xc,hitrock;
316     Uint16 c, *rawpixel;
317
318     hitrock = -1;
319     xc = XSIZE;
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);
326                 hitrock = i;
327             }
328         }
329     }
330
331     if (hitrock>=0) {
332         rock[hitrock].heat += movementrate*3;
333     }
334
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);
339
340     for (i=0; i<(xc-xship)*5; i+=10) {
341         int x,y;
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;
345     }
346
347     SDL_UnlockSurface(surf_screen);
348 }/*}}}*/
349
350
351 int makebangdots(int xbang, int ybang, int xvel, int yvel, SDL_Surface *s, int power) {/*{{{*/
352
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
355
356     int i,x,y,n,endcount;
357     Uint16 *rawpixel,c;
358     double theta,r,dx,dy;
359     int begin_generate;
360
361     begin_generate = SDL_GetTicks();
362
363     SDL_LockSurface(s);
364     rawpixel = (Uint16 *) s->pixels;
365
366     //for (n=0; n<=power/2; n++) {
367
368     endcount = 0;
369     while (endcount<3) {
370
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)) {
375
376                     theta = rnd()*M_PI*2;
377
378                     r = 1-(rnd()*rnd());
379
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;
384
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;
390
391                     bd2++;
392                     bd2 %= MAXBANGDOTS;
393
394                     // If the circular buffer is filled, who cares? They've had their chance.
395                     //if (bd2==bd1-1) goto exitloop;
396
397                 }
398             }
399         }
400
401         if (SDL_GetTicks() - begin_generate > 7) endcount++;
402
403     }
404 exitloop:
405
406     SDL_UnlockSurface(s);
407
408 }/*}}}*/
409
410 void draw_bang_dots(SDL_Surface *s) {/*{{{*/
411     int i;
412     int first_i, last_i;
413     Uint16 *rawpixel;
414     rawpixel = (Uint16 *) s->pixels;
415
416     first_i = -1;
417
418     for (i=bd1; (bd1<=bd2)?(i<bd2):(i>=bd1 && i<bd2); last_i = ++i) {
419
420         i %= MAXBANGDOTS;
421
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
424             bdot[i].active = 0;
425         }
426
427         if (bdot[i].active) {
428
429             //printf("%d %d\n",bd1,bd2);
430
431             if (first_i < 0)
432                 first_i = i;
433             //last_i = i+1;
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;
439
440             if (bdot[i].life<0)
441                 bdot[i].active = 0;
442         }
443
444         //printf("/n");
445         //exit(0);
446
447     }
448
449     if (first_i>=0) {
450         bd1 = first_i;
451         bd2 = last_i;
452         //printf("new %d %d\n",bd1,bd2);
453         //fprintf (stderr,"%d - %d\n", bd1,bd2);
454     }
455     else {
456         bd1 = 0;
457         bd2 = 0;
458         //fprintf (stderr,"reset\n");
459     }
460
461 }/*}}}*/
462
463
464 void draw_space_dots(SDL_Surface *s) {/*{{{*/
465     int i;
466     Uint16 *rawpixel;
467     rawpixel = (Uint16 *) s->pixels;
468
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) {
475                 sdot[i].y -= YSIZE;
476         } else if(sdot[i].y < 0) {
477                 sdot[i].y += YSIZE;
478         }
479         if (sdot[i].x<0)
480             sdot[i].x=XSIZE;
481     }
482 }/*}}}*/
483 void draw_engine_dots(SDL_Surface *s) {/*{{{*/
484     int i;
485     Uint16 *rawpixel;
486     rawpixel = (Uint16 *) s->pixels;
487
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)
493                 edot[i].active=0;
494             else
495                 if (edot[i].x<0 || edot[i].x>XSIZE) {
496                     edot[i].active=0;
497                 }
498                 else {
499                     int heatindex;
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];
503                 }
504         }
505     }
506 }/*}}}*/
507
508 void create_engine_dots(int newdots) {
509     int i;
510     double theta,r,dx,dy;
511
512         if(!tail_plume) return;
513
514     if (state==GAMEPLAY)
515         for (i=0; i<newdots*movementrate; i++) {
516             if (dotptr->active==0) {
517
518                 theta = rnd()*M_PI*2;
519                 r = rnd();
520                 dx = cos(theta)*r;
521                 dy = sin(theta)*r;
522
523                 dotptr->active=1;
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;
529
530                 dotptr++;
531                 if (dotptr-edot>=MAXENGINEDOTS) dotptr = edot;
532
533             }
534         }
535 }
536
537 void create_engine_dots2(int newdots, int m) {
538     int i;
539     double theta, theta2, dx, dy, adx, ady;
540
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;
544
545     for (i=0; i<newdots; i++) {
546         if (dotptr->active==0) {
547
548             theta = rnd()*M_PI*2;
549             theta2 = rnd()*M_PI*2;
550
551        dx = cos(theta) * fabs(cos(theta2));
552             dy = sin(theta) * fabs(cos(theta2));
553             adx = fabs(dx);
554             ady = fabs(dy);
555
556
557             dotptr->active=1;
558             dotptr->x=xship+surf_ship->w/2+(rnd()-0.5)*3;
559             dotptr->y=yship+surf_ship->h/2+(rnd()-0.5)*3;
560
561             switch(m) {
562                 case 0:
563                     dotptr->x-=14;
564                     dotptr->dx=-20*adx + xvel;
565                     dotptr->dy=2*dy+yvel;
566                     dotptr->life = 60 * adx;
567                     break;
568                 case 1:
569                     dotptr->dx=2*dx+xvel;
570                     dotptr->dy=-20*ady + yvel;
571                     dotptr->life = 60 * ady;
572                     break;
573                 case 2:
574                     dotptr->x+=14;
575                     dotptr->dx=20*adx + xvel;
576                     dotptr->dy=2*dy+yvel;
577                     dotptr->life = 60 * adx;
578                     break;
579                 case 3:
580                     dotptr->dx=2*dx+xvel;
581                     dotptr->dy=20*ady + yvel;
582                     dotptr->life = 60 * ady;
583                     break;
584             }
585             //dotptr->life *= 0.5 + rnd(0.5);
586             //dotptr->life=45+rnd(1)*20;
587             dotptr++;
588             if (dotptr-edot>=MAXENGINEDOTS)
589                 dotptr = edot;
590         }
591     }
592 }
593
594 int drawdots(SDL_Surface *s) {/*{{{*/
595     int m, scorepos, n;
596
597     SDL_LockSurface(s);
598     // Draw the background stars aka space dots
599     draw_space_dots(s);
600
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 ) {
603
604         SDL_UnlockSurface(s);
605
606         scorepos = XSIZE-250;
607         n = snprintf(topline, 50, "Time: ");
608         snprintscore(topline+n, 50-n, score);
609         PutString(s,scorepos,0,topline);
610
611         SDL_LockSurface(s);
612
613     }
614
615     // Draw all the engine dots
616     draw_engine_dots(s);
617
618     // Create more engine dots comin out da back
619     if (!gameover)
620         create_engine_dots(200);
621
622     // Create engine dots out the side we're moving from
623     for (m=0; m<4; m++)
624         if (maneuver & 1<<m) // 'maneuver' is a bit field
625             create_engine_dots2(80,m);
626
627     // Draw all outstanding bang dots
628     //if (bangdotlife-- > 0) 
629         draw_bang_dots(s);
630
631     SDL_UnlockSurface(s);
632 }/*}}}*/
633 char * load_file(char *s) {/*{{{*/
634     static char retval[1024];
635     snprintf(retval, 1024, "%s/%s", data_dir, s);
636     return retval;
637 }
638 /*}}}*/
639 int missing(char *dirname) {/*{{{*/
640     struct stat buf;
641     stat(dirname, &buf);
642     return (!S_ISDIR(buf.st_mode));
643 }/*}}}*/
644
645 int init(int fullscreen) {/*{{{*/
646
647     int i,j;
648     SDL_Surface *temp;
649     Uint16 *raw_pixels;
650     Uint32 flag;
651
652     read_high_score_table();
653
654     // Where are our data files?
655     // default: ./data
656     // second alternative: RD_DATADIR
657     // final alternative: /usr/share/rockdodger
658     data_dir = strdup("./data");
659     if (missing(data_dir)) {
660         char *env;
661         env = getenv("RD_DATADIR");
662         if (env != NULL) {
663             data_dir = strdup(env);
664             if (missing(data_dir)) {
665                 fprintf (stderr,"Cannot find data directory $RD_DATADIR\n");
666                 exit(-1);
667             }
668         }
669         else {
670             data_dir = strdup("/usr/share/rockdodger");
671             if (missing(data_dir)) {
672                 fprintf (stderr,"Cannot find data in %s\n", data_dir);
673                 exit(-2);
674             }
675         }
676     }
677
678     if (oss_sound_flag) {
679
680         // Initialise SDL with audio and video
681         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)!=0) {
682             oss_sound_flag=0;
683             printf ("Can't open sound, starting without it\n");
684             atexit(SDL_Quit);
685         }
686         else {
687             atexit(SDL_Quit);
688             atexit(SDL_CloseAudio);
689             oss_sound_flag = init_sound();
690         }
691
692     }
693     else {
694         // Initialise with video only
695         CONDERROR(SDL_Init(SDL_INIT_VIDEO)!=0);
696         atexit(SDL_Quit);
697     }
698
699     if (oss_sound_flag)
700         play_tune(0);
701
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);
706
707     // Set the title bar text
708     SDL_WM_SetCaption("Rock Dodgers", "rockdodgers");
709
710     NULLERROR(surf_screen);
711
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(
715             surf_screen->format,
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?
717         );
718
719     // Load the banners
720     NULLERROR(temp = IMG_Load(load_file("banners/rock.png")));
721     NULLERROR(surf_b_rock = SDL_DisplayFormat(temp));
722
723     NULLERROR(temp = IMG_Load(load_file("banners/dodgers.png")));
724     NULLERROR(surf_b_dodgers = SDL_DisplayFormat(temp));
725
726     NULLERROR(temp = IMG_Load(load_file("banners/game.png")));
727     NULLERROR(surf_b_game = SDL_DisplayFormat(temp));
728
729     NULLERROR(temp = IMG_Load(load_file("banners/over.png")));
730     NULLERROR(surf_b_over = SDL_DisplayFormat(temp));
731
732     surf_font_big = IMG_Load(load_file(BIG_FONT_FILE));
733     InitFont(surf_font_big);
734
735     // Load the spaceship graphic.
736         NULLERROR(temp = IMG_Load(load_file("sprites/ship.png")));
737         NULLERROR(surf_ship = SDL_DisplayFormat(temp));
738
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));
742
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) {
749                 blackptr->x = i;
750                 blackptr->y = j;
751                 blackptr++;
752             }
753     SDL_UnlockSurface(surf_ship);
754
755     init_engine_dots();
756     init_space_dots();
757
758     // Load all our lovely rocks
759     for (i=0; i<NROCKS; i++) {
760                 char a[100];
761
762                 sprintf(a,load_file("sprites/rock%d.png"),i);
763                 NULLERROR(temp = IMG_Load(a));
764                 NULLERROR(surf_rock[i] = SDL_DisplayFormat(temp));
765
766                 sprintf(a,load_file("sprites/deadrock%d.png"),i);
767                 NULLERROR(temp = IMG_Load(a));
768                 NULLERROR(surf_deadrock[i] = SDL_DisplayFormat(temp));
769     }
770
771     // Remove the mouse cursor
772 #ifdef SDL_DISABLE
773     SDL_ShowCursor(SDL_DISABLE);
774 #endif
775
776     return 0;
777 }/*}}}*/
778 int draw() {/*{{{*/
779     int i,n;
780     SDL_Rect src,dest;
781     struct black_point_struct *p;
782     Uint16 *raw_pixels;
783     int bang, offset, x;
784     char *text;
785     float fadegame,fadeover;
786
787     char *statedisplay, buf[1024];
788     
789     bang=0;
790
791     src.x=0;
792     src.y=0;
793     dest.x=0;
794     dest.y=0;
795
796     // Draw a fully black background
797     SDL_FillRect(surf_screen,NULL,0);
798
799
800 #ifdef DEBUG
801     // DEBUG {{{
802     // Show the current state
803     switch (state) {
804         case TITLE_PAGE:
805             statedisplay = "title_page";
806             break;
807         case GAMEPLAY:
808             statedisplay = "gameplay";
809             break;
810         case DEAD_PAUSE:
811             statedisplay = "dead_pause";
812             break;
813         case GAME_OVER:
814             statedisplay = "game_over";
815             break;
816         case HIGH_SCORE_ENTRY:
817             statedisplay = "high_score_entry";
818             break;
819         case HIGH_SCORE_DISPLAY:
820             statedisplay = "high_score_display";
821             break;
822         case DEMO:
823             statedisplay = "demo";
824             break;
825     }
826     snprintf(buf,1024, "mode=%s", statedisplay);
827     PutString(surf_screen,0,YSIZE-50,buf);
828     // }}}
829 #endif
830     
831     // Draw the background dots
832     drawdots(surf_screen);
833
834     // If it's firing, draw the laser
835     if (laser)
836         drawlaser();
837
838     // Draw ship
839     if (!gameover && (state==GAMEPLAY || state==DEMO) )  {
840         src.w = surf_ship->w;
841         src.h = surf_ship->h;
842         dest.w = src.w;
843         dest.h = src.h;
844         dest.x = (int)xship;
845         dest.y = (int)yship;
846         SDL_BlitSurface(surf_ship,&src,surf_screen,&dest);
847     }
848
849     // Draw all the rocks, in all states
850     for (i=0; i<MAXROCKS; i++) {
851         if (rock[i].active) {
852
853             src.w = rock[i].image->w;
854             src.h = rock[i].image->h;
855             dest.w = src.w;
856             dest.h = src.h;
857             dest.x = (int) rock[i].x;
858             dest.y = (int) rock[i].y;
859
860             // Draw the rock
861             SDL_BlitSurface(rock[i].image,&src,surf_screen,&dest);
862
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;
872             }
873
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) {
878                 rock[i].active=0;
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);
881             }
882
883         }
884     }
885
886     // If it's game over, show the game over graphic in the dead centre
887     switch (state) {
888
889         case GAME_OVER:
890
891             if (fadetimer<3.0/faderate) 
892                 fadegame=fadetimer/(3.0/faderate);
893             else
894                 fadegame=1.0;
895
896             if (fadetimer<3.0/faderate) 
897                 fadeover=0.0;
898             else 
899                 if (fadetimer<6.0/faderate)
900                     fadeover = ((3.0/faderate)-fadetimer)/(6.0/faderate);
901                 else
902                     fadeover = 1.0;
903
904             src.w = surf_b_game->w;
905             src.h = surf_b_game->h;
906             dest.w = src.w;
907             dest.h = src.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);
912
913             src.w = surf_b_over->w;
914             src.h = surf_b_over->h;
915             dest.w = src.w;
916             dest.h = src.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);
921             break;
922
923         case TITLE_PAGE:
924             src.w = surf_b_rock->w;
925             src.h = surf_b_rock->h;
926             dest.w = src.w;
927             dest.h = src.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;
934             dest.w = src.w;
935             dest.h = src.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);
940
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);
944
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);
949             break;
950
951         case HIGH_SCORE_ENTRY:
952
953             if (score >= high[7].score) {
954                 play_tune(2);
955                 if (SFont_Input (surf_screen, 330, 50+(scorerank+2)*font_height, 300, name)) {
956                     // Insert name into high score table
957
958                     // Lose the lowest name forever (loser!)
959                     //if (high[7].allocated)
960                     //  free(high[7].name);                 // THIS WAS CRASHING SO I REMOVED IT
961
962                     // Insert new high score
963                     high[scorerank].score = score;
964                     high[scorerank].name = strdup(name);    // MEMORY NEVER FREED!
965                     high[scorerank].allocated = 1;
966     
967                     // Set the global name string to "", ready for the next winner
968                     name[0]=0;
969     
970                     // Change state to briefly show high scores page
971                     state = HIGH_SCORE_DISPLAY;
972                     state_timeout=200;
973
974                     // Write the high score table to the file
975                     write_high_score_table();
976     
977                     // Play the title page tune
978                     play_tune(0);
979                 }
980             }
981             else {
982                 state = HIGH_SCORE_DISPLAY;
983                 state_timeout=400;
984             }
985
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++) {
990                 char s[1024];
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);
997             }
998
999     }
1000
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) {
1006             int x,y,l;
1007             Uint16 c;
1008
1009             if (initialshield>0) {
1010                 initialshield-=movementrate;
1011                 c = SDL_MapRGB(surf_screen->format,0,255,255);
1012             }
1013             else {
1014                 c = heatcolor[(int)shieldlevel];
1015                 shieldlevel-=movementrate;
1016             }
1017
1018             shieldpulse += 0.2;
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;
1025                 }
1026             }
1027         }
1028         else {
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
1035                     bang = 1;
1036                 }
1037             }
1038         }
1039         SDL_UnlockSurface(surf_screen);
1040     }
1041
1042 #ifdef DOTCOLLISION
1043     dotcollision(surf_screen); // Kill dots that are not on their spots
1044 #endif
1045
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;
1051             dest.w = src.w;
1052             dest.h = src.h;
1053             dest.x = (i+1)*(src.w+10);
1054             dest.y = 20;
1055             SDL_BlitSurface(surf_life,&src,surf_screen,&dest);
1056         }
1057
1058
1059     // Update the score
1060     /*
1061     n=SDL_GetTicks()-initticks;
1062     if (score)
1063         ticks_since_last = n-score;
1064     score = n;
1065     */
1066
1067     ticks_since_last = SDL_GetTicks()-last_ticks;
1068     last_ticks = SDL_GetTicks();
1069     if (ticks_since_last>200 || ticks_since_last<0) {
1070         movementrate = 0;
1071     }
1072     else {
1073         movementrate = ticks_since_last/50.0;
1074         if (state==GAMEPLAY)
1075             score += ticks_since_last;
1076     }
1077
1078     // Update the surface
1079     SDL_Flip(surf_screen);
1080
1081
1082     return bang;
1083 }/*}}}*/
1084 int gameloop() {/*{{{*/
1085     int i=0;
1086     Uint8 *keystate;
1087
1088
1089     for(;;) {
1090
1091         if (!paused) {
1092             // Count down the game loop timer, and change state when it gets to zero or less;
1093
1094             if ((state_timeout -= movementrate*3) < 0) {
1095                 switch(state) {
1096                     case DEAD_PAUSE:
1097                         // Create a new ship and start all over again
1098                         state = GAMEPLAY;
1099                         play_tune(1);
1100                         initialshield = 150;
1101                         xship = 10;
1102                         yship = YSIZE/2;
1103                         xvel=2;
1104                         yvel=0;
1105                         shieldlevel = 3*W;
1106                         break;
1107                     case GAME_OVER:
1108                         state = HIGH_SCORE_ENTRY;
1109                         clearBuffer();
1110                         name[0]=0;
1111                         state_timeout=5.0e6;
1112
1113                         if (score>=high[7].score) {
1114                             // Read the high score table from the storage file
1115                             read_high_score_table();
1116
1117                             // Find ranking of this score, store as scorerank
1118                             for (i=0; i<8; i++) {
1119                                 if (high[i].score <= score) {
1120                                     scorerank = i;
1121                                     break;
1122                                 }
1123                             }
1124
1125                             // Move all lower scores down a notch
1126                             for (i=7; i>=scorerank; i--)
1127                                 high[i] = high[i-1];
1128
1129                             // Insert blank high score
1130                             high[scorerank].score = score;
1131                             high[scorerank].name = "";
1132                             high[scorerank].allocated = 0;
1133                         }
1134
1135                         break;
1136                     case HIGH_SCORE_DISPLAY:
1137                         state = TITLE_PAGE;
1138                         state_timeout=500.0;
1139                         break;
1140                     case HIGH_SCORE_ENTRY:
1141                         // state = TITLE_PAGE;
1142                         // play_tune(1);
1143                         // state_timeout=100.0;
1144                         break;
1145 #ifdef DEMO_ENABLED
1146                     case TITLE_PAGE:
1147                         state = DEMO;
1148                         state_timeout=100.0;
1149                         break;
1150                     case DEMO:
1151                         state = HIGH_SCORE_DISPLAY;
1152                         state_timeout=100.0;
1153                         break;
1154 #else
1155                     case TITLE_PAGE:
1156                         state = HIGH_SCORE_DISPLAY;
1157                         state_timeout=200.0;
1158                         break;
1159 #endif
1160                 }
1161             }
1162
1163             if (--countdown<=0 && (rnd()*100.0<(rockrate+=0.025))) {
1164                 // Create a rock
1165                 rockptr++;
1166                 if (rockptr-rock>=MAXROCKS)
1167                     rockptr=rock;
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;
1173                     rockptr->heat = 0;
1174                     rockptr->image = surf_rock[rockptr->type_number];// [random()%NROCKS];
1175                     rockptr->active = 1;
1176                     rockptr->y = rnd()*(YSIZE + rockptr->image->h);
1177                 }
1178                 if (movementrate>0.1)
1179                     countdown = (int)(ROCKRATE/movementrate);
1180                 else
1181                     countdown=0;
1182             }
1183
1184             // FRICTION?
1185                 if(friction) {
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;
1190                 }
1191
1192             // INERTIA
1193             xship += xvel*movementrate;
1194             yship += yvel*movementrate;
1195
1196             // SCROLLING
1197             yscroll = yship - (YSIZE / 2);
1198             yscroll /= -15;
1199             yscroll = yscroll*movementrate;
1200             yship += yscroll;
1201             
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) {
1207                         rock[i].y -= YSIZE;
1208                         rock[i].y -= rock[i].image->w;
1209                 } else if(rock[i].y < -rock[i].image->w) {
1210                         rock[i].y += YSIZE;
1211                         rock[i].y += rock[i].image->w;
1212                 }
1213                 if (rock[i].x<-32.0)
1214                     rock[i].active=0;
1215             }
1216
1217
1218             // BOUNCE X
1219             if (xship<0 || xship>XSIZE-surf_ship->w) {
1220                 // BOUNCE from left and right wall
1221                 xship -= xvel*movementrate;
1222                 xvel *= -0.99;
1223             }
1224
1225             // BOUNCE Y
1226             if (yship<0 || yship>YSIZE-surf_ship->h) {
1227                 // BOUNCE from top and bottom wall
1228                 yship -= yvel;
1229                 yvel *= -0.99;
1230             }
1231
1232
1233             if (draw() && state==GAMEPLAY)  {
1234                 if (oss_sound_flag) {
1235                     // Play the explosion sound
1236                     play_sound(0);
1237                 }
1238                 makebangdots(xship,yship,xvel,yvel,surf_ship,30);
1239                 if (--nships<=0) {
1240                     gameover=1;
1241                     state=GAME_OVER;
1242                     state_timeout = 200.0;
1243                     fadetimer=0.0;
1244                     faderate=movementrate;
1245                 }
1246                 else {
1247                     state=DEAD_PAUSE;
1248                     state_timeout = 100.0;
1249                 }
1250             }
1251
1252             SDL_PumpEvents();
1253             keystate = SDL_GetKeyState(NULL);
1254
1255             if (state!=HIGH_SCORE_ENTRY && (keystate[SDLK_q] || keystate[SDLK_ESCAPE]))
1256                 return 0;
1257
1258             if (keystate[SDLK_SPACE] && (state==HIGH_SCORE_DISPLAY || state==TITLE_PAGE || state==DEMO)) {
1259
1260                         for (i=0; i<MAXROCKS; i++) rock[i].active=0;
1261
1262                         rockrate=54.0;
1263                         rockspeed=5.0;
1264
1265                         nships = 4;
1266                         score = 0;
1267
1268                         state = GAMEPLAY;
1269                         play_tune(1);
1270
1271                         xvel=-1;
1272                         gameover=0;
1273                         yvel=0;
1274                         xship=0;
1275                         yship=YSIZE/2;
1276                         shieldlevel = 3*W;
1277                         initialshield = 0;
1278
1279             }
1280
1281             maneuver=0;
1282             laser=0;
1283         }
1284         else {
1285             SDL_PumpEvents();
1286             keystate = SDL_GetKeyState(NULL);
1287         }
1288
1289         if (state==GAMEPLAY) {
1290             if (!gameover) {
1291
1292                 if (!paused) {
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];
1302                 }
1303
1304                 if (keystate[SDLK_p])   {
1305                     if (!pausedown) {
1306                         paused = !paused;
1307                         if (paused) {
1308                             SDL_Rect src,dest;
1309                             src.w = surf_b_rock->w;
1310                             src.h = surf_b_rock->h;
1311                             dest.w = src.w;
1312                             dest.h = src.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);
1318                             printf("paused\n");
1319                         }
1320                         else {
1321                             printf ("not paused\n");
1322                         }
1323                         pausedown=1;
1324                     }
1325                 }
1326                 else {
1327                     pausedown=0;
1328                 }
1329
1330             }
1331             else {
1332                 shieldsup = 0;
1333                 paused = 0;
1334                 pausedown = 0;
1335             }
1336         }
1337
1338         // DEBUG mode to slow down the action, and see if this game is playable on a 486
1339         if (fast)
1340             SDL_Delay (100);
1341     }
1342 }/*}}}*/
1343 main(int argc, char **argv) {/*{{{*/
1344     int i, x, fullscreen;
1345
1346     fullscreen=0;
1347         tail_plume=0;
1348         friction=0;
1349     oss_sound_flag=1;
1350
1351     while ((x=getopt(argc,argv,"efhsp"))>=0)
1352         switch(x) {
1353                 case 'e':  // engine
1354                         tail_plume = 1;
1355                         break;
1356                 case 'f':  // fullscreen
1357                         fullscreen = 1;
1358                         break;
1359             case 'h':  // help
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");
1366                         exit(0);
1367                         break;
1368                 case 'p':  // physics
1369                         friction = 1;
1370                         break;
1371             case 's':  // silent
1372                         oss_sound_flag = 0;
1373                         break;
1374         }
1375
1376     if (init(fullscreen)) {
1377         printf ("ta: '%s'\n",initerror);
1378         return 1;
1379     }
1380
1381     while(1) {
1382         for (i=0; i<MAXROCKS; i++)
1383             rock[i].active=0;
1384         rockrate=54.0;
1385         rockspeed=5.0;
1386         initticks = SDL_GetTicks();
1387         if (gameloop()==0) break;
1388         printf ("score=%d\n",score);
1389         SDL_Delay(1000);
1390     }
1391
1392     return 0;
1393 }/*}}}*/
1394
1395 /*
1396  * $Id: main.c,v 1.22 2002/02/15 20:26:45 pad Exp $
1397  * $Log: main.c,v $
1398  * Revision 1.22  2002/02/15 20:26:45  pad
1399  * Update - explosion time limits (ergh) and stuff
1400  *
1401  * Revision 1.21  2002/01/26 14:13:27  pad
1402  * Released to pcholt.com as 0.4.0a
1403  *
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
1407  *
1408  * Revision 1.19  2002/01/17 19:38:45  pad
1409  * Bang noise (must add more noises)
1410  *
1411  * Revision 1.18  2002/01/16 01:34:28  pad
1412  * Rocks now change colour smoothly while being heated.
1413  *
1414  * Revision 1.17  2002/01/15 21:56:51  pad
1415  * Lasers work, and rocks blow up, but unspectacularly.
1416  *
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
1421  *
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
1426  *
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.
1430  *
1431  * Revision 1.13  2001/10/07 19:23:28  pad
1432  * SDL_mixer, music and sound added
1433  *
1434  * Revision 1.12  2001/09/29 23:28:27  pad
1435  * 0.1.8b release
1436  * {{{
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.
1440  *
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".
1444  *
1445  * Revision 1.9  2001/09/18 22:41:22  pad
1446  * The score stays on the screen no matter what the game mode.
1447  *
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.
1451  *
1452  * Revision 1.6  2001/09/08 23:01:02  pad
1453  * Version number on start screen, from Makefile
1454  * Makefile 'make package' works
1455  *
1456  * Revision 1.5  2001/09/08 00:13:03  pad
1457  * State table
1458  * Title screen
1459  * Revamped scoring system
1460  * Looks nice!
1461  *
1462  * Revision 1.4  2001/09/06 21:42:05  pad
1463  * Score is displayed using the lovely SFont library.
1464  *
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.
1468  *
1469  * Functions normalised - aim should be to have each function perform
1470  * one action and one action alone. This is not yet complete.
1471  *
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..
1475  *
1476  }}}
1477  */