JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
f7e5bd4ace922525a43a73690dc2aceff78bf671
[vor.git] / main.c
1 /* Variations on RockDodger
2  * Space Rocks copyright (C) 2001 Paul Holt <pad@pcholt.com>
3  *
4  * Project fork 2004, Jason Woofenden and Joshua Grams.
5  * (a whole bunch of modifications and project rename)
6
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.
11  *
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.
16  *
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
20  */
21
22 #undef DEBUG
23
24 extern int font_height;
25 void clearBuffer();
26
27 // includes {{{
28 #include <SDL/SDL.h>
29 #include <SDL/SDL_image.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 #include <stdarg.h>
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39
40 #include "SFont.h"
41 // }}}
42 // constants {{{
43 #define XSIZE 640
44 #define YSIZE 480
45 #define NROCKS 6        // Number of rock image files, not number of rocks visible
46 #define MAXROCKS 120 // MAX Rocks
47 #define MAXROCKHEIGHT 100
48 #define ROCKRATE 2
49 #define MAXBLACKPOINTS 500
50 #define MAXENGINEDOTS 5000
51 #define MAXBANGDOTS 50000
52 #define MAXSPACEDOTS 2000
53 #define W 100
54 #define M 255
55 #define BIG_FONT_FILE "fonts/score.png"
56 // }}}
57 // macros {{{
58 #define CONDERROR(a) if((a)) {initerror = strdup(SDL_GetError());return 1;}
59 #define NULLERROR(a) CONDERROR((a) == NULL)
60 // }}}
61
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
67         float x,y,xvel,yvel;
68         int active;
69         SDL_Surface *image;
70         int type_number;
71         float heat;
72 }; 
73 struct black_point_struct {
74         int x,y;
75 };
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.
80         float x,y,dx,dy;
81         Uint16 c; // when zero, use heatcolor[bangdotlife]
82         float life;     // When reduced to 0, set active = 0
83         int active;
84         float decay;// Amount by which to reduce life each time dot is drawn
85 };
86 struct enginedots {
87         // Engine dots stream out the back of the ship, getting darker as they go.
88         int active;
89         float x,y,dx,dy;
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
93 };
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.
97         float x,y,dx;
98         Uint16 color;
99 };
100 // High score table {{{
101 struct highscore {
102         int score;
103         char *name;
104         int allocated;
105 } high[] = {
106         {13000,"Pad",0},
107         {12500,"Pad",0},
108         {6500,"Pad",0},
109         {5000,"Pad",0},
110         {3000,"Pad",0},
111         {2500,"Pad",0},
112         {2000,"Pad",0},
113         {1500,"Pad",0}
114 };
115 // }}}
116
117 // ************************************* VARS
118 // SDL_Surface global variables {{{
119 SDL_Surface 
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
131 // }}}
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];
138 // }}}
139 // Other global variables {{{
140 char topline[1024];
141 char *initerror = "";
142 char name[1024], debug1[1024];
143
144 float xship,yship = 240.0;      // X position, 0..XSIZE
145 float xvel,yvel;        // Change in X position per tick.
146 float rockrate,rockspeed;
147 float movementrate;
148 float shieldlevel, shieldpulse = 0;
149 float yscroll;
150
151 int nships,score,initticks,ticks_since_last, last_ticks;
152 int initialshield, gameover, fast;
153 int countdown = 0;
154 int maneuver = 0;
155 int laser = 0;
156 int shieldsup = 0;
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?
160 int scorerank;
161 float fadetimer = 0,faderate;
162
163 int pausedown = 0,paused = 0;
164
165 // bangdot start (bd1) and end (bd2) position:
166 int bd1 = 0, bd2 = 0;
167
168 int xoffset[NROCKS][MAXROCKHEIGHT];
169
170 enum states {
171         TITLE_PAGE,
172         GAMEPLAY,
173         DEAD_PAUSE,
174         GAME_OVER,
175         HIGH_SCORE_ENTRY,
176         HIGH_SCORE_DISPLAY,
177         DEMO
178 };
179 enum states state = TITLE_PAGE;
180 float state_timeout = 600.0;
181
182 const int fakesin[] = {0,1,0,-1};
183 const int fakecos[] = {1,0,-1,0};
184 #define NSEQUENCE 2
185 char *sequence[] = {
186         "Press SPACE to start",
187         "http://qualdan.com/vor/"
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/vor/.highscore",mode)) {
230                 umask(mask);
231                 return f;
232         }
233         else {
234                 char s[1024];
235                 umask(0177);
236                 sprintf(s,"%s/.vor-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                         }
258                         if(high[i].allocated) {
259                                 free(high[i].name);
260                         }
261                         high[i].name = strdup(s);
262                         high[i].score = highscore;
263                         high[i].allocated = 1;
264                 }
265                 fclose(f);
266         }
267 }
268 void write_high_score_table() {
269         FILE *f;
270         int i;
271         if(f = hs_fopen("w")) {
272                 // If the file exists, write to it
273                 for(i = 0; i<8; i ++ ) {
274                         fprintf (f, "%d %s\n", high[i].score, high[i].name);
275                 }
276                 fclose(f);
277         }
278 }
279 void snprintscore(char *s, size_t n, int score) {
280         int min = score/60000;
281         int sec = score/1000%60;
282         int tenths = score%1000/100;
283         if(min) {
284                 snprintf(s, n, "%2d:%.2d.%d", min, sec, tenths);
285         } else {
286                 snprintf(s, n, "  %2d.%d", sec, tenths);
287         }
288 }
289 float rnd() {
290         return (float)random()/(float)RAND_MAX;
291 }
292 void init_engine_dots() {
293         int i;
294         for(i = 0; i<MAXENGINEDOTS; i ++ ) {
295                 edot[i].active = 0;
296         }
297 }
298 void init_space_dots() {
299         int i,intensity;
300         for(i = 0; i<MAXSPACEDOTS; i ++ ) {
301                 float r;
302
303                 sdot[i].x = rnd()*(XSIZE-5);
304                 sdot[i].y = rnd()*(YSIZE-5);
305
306                 r = rnd()*rnd();
307
308                 sdot[i].dx = -r*4;
309                 // -1/((1-r) + .3);
310                 intensity = (int)(r*180 + 70);
311                 sdot[i].color = SDL_MapRGB(surf_screen->format,intensity,intensity,intensity);
312
313         }
314 }
315
316 int drawlaser() {
317         int i,xc,hitrock;
318         Uint16 c, *rawpixel;
319
320         hitrock = -1;
321         xc = XSIZE;
322         // let xc = x coordinate of the collision between the laser and a space rock
323         // 1. Calculate xc and determine the asteroid that was hit
324         for(i = 0; i<MAXROCKS; i ++ ) {
325                 if(rock[i].active) {
326                         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) {
327                                 xc = rock[i].x + (rock[i].image->w/2);
328                                 hitrock = i;
329                         }
330                 }
331         }
332
333         if(hitrock>= 0) {
334                 rock[hitrock].heat += movementrate*3;
335         }
336
337         // Plot a number of random dots between xship and XSIZE
338         SDL_LockSurface(surf_screen);
339         rawpixel = (Uint16 *) surf_screen->pixels;
340         c = SDL_MapRGB(surf_ship->format,rnd()*128,128 + rnd()*120,rnd()*128);
341
342         for(i = 0; i<(xc-xship)*5; i += 10) {
343                 int x,y;
344                 x = rnd()*(xc-(xship + 32)) + xship + 32;
345                 y = yship + 12 + (rnd()-0.5)*1.5;
346                 rawpixel[surf_screen->pitch/2*y + x] = c;
347         }
348
349         SDL_UnlockSurface(surf_screen);
350 }
351
352
353 int makebangdots(int xbang, int ybang, int xvel, int yvel, SDL_Surface *s, int power) {
354
355         // TODO - stop generating dots after a certain amount of time has passed, to cope with slower CPUs.
356         // TODO - generate and display dots in a circular buffer
357
358         int i,x,y,n,endcount;
359         Uint16 *rawpixel,c;
360         double theta,r,dx,dy;
361         int begin_generate;
362
363         begin_generate = SDL_GetTicks();
364
365         SDL_LockSurface(s);
366         rawpixel = (Uint16 *) s->pixels;
367
368         //for(n = 0; n<= power/2; n ++ ) {
369
370         endcount = 0;
371         while (endcount<3) {
372
373         for(x = 0; x<s->w; x ++ ) {
374                 for(y = 0; y<s->h; y ++ ) {
375                         c = rawpixel[s->pitch/2*y + x];
376                         if(c && c != SDL_MapRGB(s->format,0,255,0)) {
377
378                                 theta = rnd()*M_PI*2;
379
380                                 r = 1-(rnd()*rnd());
381
382                                 bdot[bd2].dx = (power/50.0)*45.0*cos(theta)*r + xvel;
383                                 bdot[bd2].dy = (power/50.0)*45.0*sin(theta)*r + yvel;
384                                 bdot[bd2].x = x + xbang;
385                                 bdot[bd2].y = y + ybang;
386
387                                 // Replace the last few bang dots with the pixels from the exploding object
388                                 bdot[bd2].c = (endcount>0)?c:0;
389                                 bdot[bd2].life = 100;
390                                 bdot[bd2].decay = rnd()*3 + 1;
391                                 bdot[bd2].active = 1;
392
393                                 bd2 ++ ;
394                                 bd2 %= MAXBANGDOTS;
395
396                                 // If the circular buffer is filled, who cares? They've had their chance.
397                                 //if(bd2 == bd1-1) goto exitloop;
398
399                         }
400                 }
401         }
402
403         if(SDL_GetTicks() - begin_generate > 7) endcount ++ ;
404
405         }
406 exitloop:
407
408         SDL_UnlockSurface(s);
409
410 }
411
412 void draw_bang_dots(SDL_Surface *s) {
413         int i;
414         int first_i, last_i;
415         Uint16 *rawpixel;
416         rawpixel = (Uint16 *) s->pixels;
417
418         first_i = -1;
419
420         for(i = bd1; (bd1 <= bd2)?(i<bd2):(i >= bd1 && i < bd2); last_i =  ++i) {
421
422                 i %= MAXBANGDOTS;
423
424                 if(bdot[i].x<= 0 || bdot[i].x>= XSIZE || bdot[i].y<= 0 || bdot[i].y>= YSIZE) {
425                         // If the dot has drifted outside the perimeter, kill it
426                         bdot[i].active = 0;
427                 }
428
429                 if(bdot[i].active) {
430                         if(first_i < 0)
431                         first_i = i;
432                         //last_i = i + 1;
433                         rawpixel[(int)(s->pitch/2*(int)(bdot[i].y)) + (int)(bdot[i].x)] = bdot[i].c ? bdot[i].c : heatcolor[(int)(bdot[i].life*3)];
434                         bdot[i].life-= bdot[i].decay;
435                         bdot[i].x += bdot[i].dx*movementrate;
436                         bdot[i].y += bdot[i].dy*movementrate + yscroll;
437
438                         if(bdot[i].life<0)
439                         bdot[i].active = 0;
440                 }
441         }
442
443         if(first_i>= 0) {
444                 bd1 = first_i;
445                 bd2 = last_i;
446         }
447         else {
448                 bd1 = 0;
449                 bd2 = 0;
450         }
451
452 }
453
454
455 void draw_space_dots(SDL_Surface *s) {
456         int i;
457         Uint16 *rawpixel;
458         rawpixel = (Uint16 *) s->pixels;
459
460         for(i = 0; i<MAXSPACEDOTS; i ++ ) {
461                 if(sdot[i].y<0) {
462                         sdot[i].y = 0;
463                 }
464                 rawpixel[(int)(s->pitch/2*(int)sdot[i].y) + (int)(sdot[i].x)] = sdot[i].color;
465                 sdot[i].x += sdot[i].dx*movementrate;
466                 sdot[i].y += yscroll;
467                 if(sdot[i].y > YSIZE) {
468                         sdot[i].y -= YSIZE;
469                 } else if(sdot[i].y < 0) {
470                         sdot[i].y += YSIZE;
471                 }
472                 if(sdot[i].x<0) {
473                         sdot[i].x = XSIZE;
474                 }
475         }
476 }
477
478 void draw_engine_dots(SDL_Surface *s) {
479         int i;
480         Uint16 *rawpixel;
481         rawpixel = (Uint16 *) s->pixels;
482
483         for(i = 0; i<MAXENGINEDOTS; i ++ ) {
484                 if(edot[i].active) {
485                         edot[i].x += edot[i].dx*movementrate;
486                         edot[i].y += edot[i].dy*movementrate + yscroll;
487                         if((edot[i].life-= movementrate*3)<0 || edot[i].y<0 || edot[i].y>YSIZE) {
488                                 edot[i].active = 0;
489                         } else if(edot[i].x<0 || edot[i].x>XSIZE) {
490                                 edot[i].active = 0;
491                         } else {
492                                 int heatindex;
493                                 heatindex = edot[i].life * 6;
494                                 //rawpixel[(int)(s->pitch/2*(int)(edot[i].y)) + (int)(edot[i].x)] = lifecolor[(int)(edot[i].life)];
495                                 rawpixel[(int)(s->pitch/2*(int)(edot[i].y)) + (int)(edot[i].x)] = heatindex>3*W ? heatcolor[3*W-1] : heatcolor[heatindex];
496                         }
497                 }
498         }
499 }
500
501 void create_engine_dots(int newdots) {
502         int i;
503         double theta,r,dx,dy;
504
505         if(!tail_plume) return;
506
507         if(state == GAMEPLAY) {
508                 for(i = 0; i<newdots*movementrate; i ++ ) {
509                         if(dotptr->active == 0) {
510                                 theta = rnd()*M_PI*2;
511                                 r = rnd();
512                                 dx = cos(theta)*r;
513                                 dy = sin(theta)*r;
514
515                                 dotptr->active = 1;
516                                 dotptr->x = xship + surf_ship->w/2-14;
517                                 dotptr->y = yship + surf_ship->h/2 + (rnd()-0.5)*5-1;
518                                 dotptr->dx = 10*(dx-1.5) + xvel;
519                                 dotptr->dy = 1*dy + yvel;
520                                 dotptr->life = 45 + rnd(1)*5;
521
522                                 dotptr ++ ;
523                                 if(dotptr-edot>= MAXENGINEDOTS) {
524                                         dotptr = edot;
525                                 }
526                         }
527                 }
528         }
529 }
530
531 void create_engine_dots2(int newdots, int m) {
532         int i;
533         double theta, theta2, dx, dy, adx, ady;
534
535         // Don't create fresh engine dots when
536         // the game is not being played and a demo is not beng shown
537         if(state!= GAMEPLAY && state!= DEMO) return;
538
539         for(i = 0; i<newdots; i ++ ) {
540                 if(dotptr->active == 0) {
541                         theta = rnd()*M_PI*2;
542                         theta2 = rnd()*M_PI*2;
543
544                         dx = cos(theta) * fabs(cos(theta2));
545                         dy = sin(theta) * fabs(cos(theta2));
546                         adx = fabs(dx);
547                         ady = fabs(dy);
548
549
550                         dotptr->active = 1;
551                         dotptr->x = xship + surf_ship->w/2 + (rnd()-0.5)*3;
552                         dotptr->y = yship + surf_ship->h/2 + (rnd()-0.5)*3;
553
554                         switch(m) {
555                                 case 0:
556                                         dotptr->x-= 14;
557                                         dotptr->dx = -20*adx + xvel;
558                                         dotptr->dy = 2*dy + yvel;
559                                         dotptr->life = 60 * adx;
560                                 break;
561                                 case 1:
562                                         dotptr->dx = 2*dx + xvel;
563                                         dotptr->dy = -20*ady + yvel;
564                                         dotptr->life = 60 * ady;
565                                 break;
566                                 case 2:
567                                         dotptr->x += 14;
568                                         dotptr->dx = 20*adx + xvel;
569                                         dotptr->dy = 2*dy + yvel;
570                                         dotptr->life = 60 * adx;
571                                 break;
572                                 case 3:
573                                         dotptr->dx = 2*dx + xvel;
574                                         dotptr->dy = 20*ady + yvel;
575                                         dotptr->life = 60 * ady;
576                                 break;
577                         }
578                         dotptr ++ ;
579                         if(dotptr-edot>= MAXENGINEDOTS) {
580                                 dotptr = edot;
581                         }
582                 }
583         }
584 }
585
586 int drawdots(SDL_Surface *s) {
587         int m, scorepos, n;
588
589         SDL_LockSurface(s);
590         // Draw the background stars aka space dots
591         draw_space_dots(s);
592
593         // Draw the score when playing the game or whn the game is freshly over
594         if(1 || state == GAMEPLAY || state == DEAD_PAUSE || state == GAME_OVER ) {
595                 SDL_UnlockSurface(s);
596
597                 scorepos = XSIZE-250;
598                 n = snprintf(topline, 50, "Time: ");
599                 snprintscore(topline + n, 50-n, score);
600                 PutString(s,scorepos,0,topline);
601
602                 SDL_LockSurface(s);
603         }
604
605         // Draw all the engine dots
606         draw_engine_dots(s);
607
608         // Create more engine dots comin out da back
609         if(!gameover)
610         create_engine_dots(200);
611
612         // Create engine dots out the side we're moving from
613         for(m = 0; m<4; m ++ ) {
614                 if(maneuver & 1<<m) { // 'maneuver' is a bit field
615                         create_engine_dots2(80,m);
616                 }
617         }
618
619         // Draw all outstanding bang dots
620         //if(bangdotlife-- > 0) 
621         draw_bang_dots(s);
622
623         SDL_UnlockSurface(s);
624 }
625
626 char * load_file(char *s) {
627         static char retval[1024];
628         snprintf(retval, 1024, "%s/%s", data_dir, s);
629         return retval;
630 }
631
632
633 int missing(char *dirname) {
634         struct stat buf;
635         stat(dirname, &buf);
636         return (!S_ISDIR(buf.st_mode));
637 }
638
639 int init(int fullscreen) {
640
641         int i,j;
642         SDL_Surface *temp;
643         Uint16 *raw_pixels;
644         Uint32 flag;
645
646         read_high_score_table();
647
648         // Where are our data files?
649         // default: ./data
650         // second alternative: RD_DATADIR
651         // final alternative: /usr/share/vor
652         data_dir = strdup("./data");
653         if(missing(data_dir)) {
654                 char *env;
655                 env = getenv("RD_DATADIR");
656                 if(env != NULL) {
657                         data_dir = strdup(env);
658                         if(missing(data_dir)) {
659                                 fprintf (stderr,"Cannot find data directory $RD_DATADIR\n");
660                                 exit(-1);
661                         }
662                 } else {
663                         data_dir = strdup("/usr/share/vor");
664                         if(missing(data_dir)) {
665                                 fprintf (stderr,"Cannot find data in %s\n", data_dir);
666                                 exit(-2);
667                         }
668                 }
669         }
670
671         if(oss_sound_flag) {
672
673         // Initialise SDL with audio and video
674         if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)!= 0) {
675                 oss_sound_flag = 0;
676                 printf ("Can't open sound, starting without it\n");
677                 atexit(SDL_Quit);
678         } else {
679                 atexit(SDL_Quit);
680                 atexit(SDL_CloseAudio);
681                 oss_sound_flag = init_sound();
682         }
683
684         } else {
685                 // Initialise with video only
686                 CONDERROR(SDL_Init(SDL_INIT_VIDEO)!= 0);
687                 atexit(SDL_Quit);
688         }
689
690         if(oss_sound_flag)
691         play_tune(0);
692
693         // Attempt to get the required video size
694         flag = SDL_DOUBLEBUF | SDL_HWSURFACE;
695         if(fullscreen) flag |= SDL_FULLSCREEN;
696         surf_screen = SDL_SetVideoMode(XSIZE,YSIZE,16,flag);
697
698         // Set the title bar text
699         SDL_WM_SetCaption("Rock Dodgers", "rockdodgers");
700
701         NULLERROR(surf_screen);
702
703         // Set the heat color from the range 0 (cold) to 300 (blue-white)
704         for(i = 0; i<W*3; i ++ ) {
705                 heatcolor[i] = SDL_MapRGB(
706                         surf_screen->format,
707                         (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?
708                 );
709         }
710
711         // Load the banners
712         NULLERROR(temp = IMG_Load(load_file("banners/variations.png")));
713         NULLERROR(surf_b_variations = SDL_DisplayFormat(temp));
714
715         NULLERROR(temp = IMG_Load(load_file("banners/on.png")));
716         NULLERROR(surf_b_on = SDL_DisplayFormat(temp));
717
718         NULLERROR(temp = IMG_Load(load_file("banners/rockdodger.png")));
719         NULLERROR(surf_b_rockdodger = SDL_DisplayFormat(temp));
720
721         NULLERROR(temp = IMG_Load(load_file("banners/game.png")));
722         NULLERROR(surf_b_game = SDL_DisplayFormat(temp));
723
724         NULLERROR(temp = IMG_Load(load_file("banners/over.png")));
725         NULLERROR(surf_b_over = SDL_DisplayFormat(temp));
726
727         surf_font_big = IMG_Load(load_file(BIG_FONT_FILE));
728         InitFont(surf_font_big);
729
730         // Load the spaceship graphic.
731         NULLERROR(temp = IMG_Load(load_file("sprites/ship.png")));
732         NULLERROR(surf_ship = SDL_DisplayFormat(temp));
733
734         // Load the life indicator (small ship) graphic.
735         NULLERROR(temp = IMG_Load(load_file("indicators/life.png")));
736         NULLERROR(surf_life = SDL_DisplayFormat(temp));
737
738         // Create the array of black points;
739         SDL_LockSurface(surf_ship);
740         raw_pixels = (Uint16 *) surf_ship->pixels;
741         for(i = 0; i<surf_ship->w; i ++ ) {
742                 for(j = 0; j<surf_ship->h; j ++ ) {
743                         if(raw_pixels[j*(surf_ship->pitch)/2 + i] == 0) {
744                                 blackptr->x = i;
745                                 blackptr->y = j;
746                                 blackptr ++ ;
747                         }
748                 }
749         }
750
751         SDL_UnlockSurface(surf_ship);
752
753         init_engine_dots();
754         init_space_dots();
755
756         // Load all our lovely rocks
757         for(i = 0; i<NROCKS; i ++ ) {
758                 char a[100];
759
760                 sprintf(a,load_file("sprites/rock%d.png"),i);
761                 NULLERROR(temp = IMG_Load(a));
762                 NULLERROR(surf_rock[i] = SDL_DisplayFormat(temp));
763
764                 sprintf(a,load_file("sprites/deadrock%d.png"),i);
765                 NULLERROR(temp = IMG_Load(a));
766                 NULLERROR(surf_deadrock[i] = SDL_DisplayFormat(temp));
767         }
768
769         // Remove the mouse cursor
770 #ifdef SDL_DISABLE
771         SDL_ShowCursor(SDL_DISABLE);
772 #endif
773
774         return 0;
775 }
776 int draw() {
777         int i,n;
778         SDL_Rect src,dest;
779         struct black_point_struct *p;
780         Uint16 *raw_pixels;
781         int bang, offset, x;
782         char *text;
783         float fadegame,fadeover;
784
785         char *statedisplay, buf[1024];
786         
787         bang = 0;
788
789         src.x = 0;
790         src.y = 0;
791         dest.x = 0;
792         dest.y = 0;
793
794         // Draw a fully black background
795         SDL_FillRect(surf_screen,NULL,0);
796
797
798 #ifdef DEBUG
799         // DEBUG {{{
800         // Show the current state
801         switch (state) {
802                 case TITLE_PAGE:
803                         statedisplay = "title_page";
804                 break;
805                 case GAMEPLAY:
806                         statedisplay = "gameplay";
807                 break;
808                 case DEAD_PAUSE:
809                         statedisplay = "dead_pause";
810                 break;
811                 case GAME_OVER:
812                         statedisplay = "game_over";
813                 break;
814                 case HIGH_SCORE_ENTRY:
815                         statedisplay = "high_score_entry";
816                 break;
817                 case HIGH_SCORE_DISPLAY:
818                         statedisplay = "high_score_display";
819                 break;
820                 case DEMO:
821                         statedisplay = "demo";
822                 break;
823         }
824         snprintf(buf,1024, "mode = %s", statedisplay);
825         PutString(surf_screen,0,YSIZE-50,buf);
826         // }}}
827 #endif
828         
829         // Draw the background dots
830         drawdots(surf_screen);
831
832         // If it's firing, draw the laser
833         if(laser) {
834                 drawlaser();
835         }
836
837         // Draw ship
838         if(!gameover && (state == GAMEPLAY || state == DEMO) ) {
839                 src.w = surf_ship->w;
840                 src.h = surf_ship->h;
841                 dest.w = src.w;
842                 dest.h = src.h;
843                 dest.x = (int)xship;
844                 dest.y = (int)yship;
845                 SDL_BlitSurface(surf_ship,&src,surf_screen,&dest);
846         }
847
848         // Draw all the rocks, in all states
849         for(i = 0; i<MAXROCKS; i ++ ) {
850                 if(rock[i].active) {
851
852                         src.w = rock[i].image->w;
853                         src.h = rock[i].image->h;
854                         dest.w = src.w;
855                         dest.h = src.h;
856                         dest.x = (int) rock[i].x;
857                         dest.y = (int) rock[i].y;
858
859                         // Draw the rock
860                         SDL_BlitSurface(rock[i].image,&src,surf_screen,&dest);
861
862                         // Draw the heated part of the rock, in an alpha which reflects the
863                         // amount of heat in the rock.
864                         if(rock[i].heat>0) {
865                                 SDL_Surface *deadrock;
866                                 deadrock = surf_deadrock[rock[i].type_number];
867                                 SDL_SetAlpha(deadrock,SDL_SRCALPHA,rock[i].heat*255/rock[i].image->h);
868                                 dest.x = (int) rock[i].x;  // kludge
869                                 SDL_BlitSurface(deadrock,&src,surf_screen,&dest);
870                                 if(rnd()<0.3) {
871                                         rock[i].heat-= movementrate;
872                                 }
873                         }
874
875                         // If the rock is heated past a certain point, the water content of
876                         // the rock flashes to steam, releasing enough energy to destroy
877                         // the rock in spectacular fashion.
878                         if(rock[i].heat>rock[i].image->h) {
879                                 rock[i].active = 0;
880                                 play_sound(1 + (int)(rnd()*3));
881                                 makebangdots(rock[i].x,rock[i].y,rock[i].xvel,rock[i].yvel,rock[i].image,10);
882                         }
883
884                 }
885         }
886
887         // If it's game over, show the game over graphic in the dead centre
888         switch (state) {
889                 case GAME_OVER:
890                         if(fadetimer<3.0/faderate) {
891                                 fadegame = fadetimer/(3.0/faderate);
892                         } else {
893                                 fadegame = 1.0;
894                         }
895
896                         if(fadetimer<3.0/faderate) {
897                                 fadeover = 0.0;
898                         } else if(fadetimer<6.0/faderate) {
899                                 fadeover = ((3.0/faderate)-fadetimer)/(6.0/faderate);
900                         } else {
901                                 fadeover = 1.0;
902                         }
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
925                         src.w = surf_b_variations->w;
926                         src.h = surf_b_variations->h;
927                         dest.w = src.w;
928                         dest.h = src.h;
929                         dest.x = (XSIZE-src.w)/2 + cos(fadetimer/6.5)*10;
930                         dest.y = (YSIZE/2-src.h)/2 + sin(fadetimer/5.0)*10;
931                         SDL_SetAlpha(surf_b_variations, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer += movementrate/2.0)));
932                         SDL_BlitSurface(surf_b_variations,&src,surf_screen,&dest);
933
934                         src.w = surf_b_on->w;
935                         src.h = surf_b_on->h;
936                         dest.w = src.w;
937                         dest.h = src.h;
938                         dest.x = (XSIZE-src.w)/2 + cos((fadetimer + 1.0)/6.5)*10;
939                         dest.y = (YSIZE/2-src.h)/2 + surf_b_variations->h + 20 + sin((fadetimer + 1.0)/5.0)*10;
940                         SDL_SetAlpha(surf_b_on, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer-1.0)));
941                         SDL_BlitSurface(surf_b_on,&src,surf_screen,&dest);
942
943                         src.w = surf_b_rockdodger->w;
944                         src.h = surf_b_rockdodger->h;
945                         dest.w = src.w;
946                         dest.h = src.h;
947                         dest.x = (XSIZE-src.w)/2 + cos((fadetimer + 2.0)/6.5)*10;
948                         dest.y = (YSIZE/2-src.h)/2 + surf_b_variations->h + surf_b_on->h + 40 + sin((fadetimer + 2.0)/5)*10;
949                         SDL_SetAlpha(surf_b_rockdodger, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer-2.0)));
950                         SDL_BlitSurface(surf_b_rockdodger,&src,surf_screen,&dest);
951
952                         text = "Version " VERSION;
953                         x = (XSIZE-SFont_wide(text))/2 + sin(fadetimer/4.5)*10;
954                         PutString(surf_screen,x,YSIZE-50 + sin(fadetimer/2)*5,text);
955
956                         text = sequence[(int)(fadetimer/40)%NSEQUENCE];
957                         //text = "Press SPACE to start!";
958                         x = (XSIZE-SFont_wide(text))/2 + cos(fadetimer/4.5)*10;
959                         PutString(surf_screen,x,YSIZE-100 + cos(fadetimer/3)*5,text);
960                 break;
961
962                 case HIGH_SCORE_ENTRY:
963
964                         if(score >= high[7].score) {
965                                 play_tune(2);
966                                 if(SFont_Input (surf_screen, 330, 50 + (scorerank + 2)*font_height, 300, name)) {
967                                         // Insert name into high score table
968
969                                         // Lose the lowest name forever (loser!)
970                                         //if(high[7].allocated)
971                                         //      free(high[7].name);                     // THIS WAS CRASHING SO I REMOVED IT
972
973                                         // Insert new high score
974                                         high[scorerank].score = score;
975                                         high[scorerank].name = strdup(name);    // MEMORY NEVER FREED!
976                                         high[scorerank].allocated = 1;
977                         
978                                         // Set the global name string to "", ready for the next winner
979                                         name[0] = 0;
980                         
981                                         // Change state to briefly show high scores page
982                                         state = HIGH_SCORE_DISPLAY;
983                                         state_timeout = 200;
984
985                                         // Write the high score table to the file
986                                         write_high_score_table();
987                         
988                                         // Play the title page tune
989                                         play_tune(0);
990                                 }
991                         } else {
992                                 state = HIGH_SCORE_DISPLAY;
993                                 state_timeout = 400;
994                         }
995                 // FALL THROUGH
996
997                 case HIGH_SCORE_DISPLAY:
998                         // Display de list o high scores mon.
999                         PutString(surf_screen,180,50,"High scores");
1000                         for(i = 0; i<8; i ++ ) {
1001                                 char s[1024];
1002                                 sprintf(s, "#%1d",i + 1);
1003                                 PutString(surf_screen, 150, 50 + (i + 2)*font_height,s);
1004                                 snprintscore(s, 1024, high[i].score);
1005                                 PutString(surf_screen, 200, 50 + (i + 2)*font_height,s);
1006                                 sprintf(s, "%3s", high[i].name);
1007                                 PutString(surf_screen, 330, 50 + (i + 2)*font_height,s);
1008                         }
1009
1010         }
1011
1012         if(!gameover && state == GAMEPLAY) {
1013                 // Show the freaky shields
1014                 SDL_LockSurface(surf_screen);
1015                 raw_pixels = (Uint16 *) surf_screen->pixels;
1016                 if(initialshield>0 || shieldsup && shieldlevel>0) {
1017                         int x,y,l;
1018                         Uint16 c;
1019
1020                         if(initialshield>0) {
1021                                 initialshield-= movementrate;
1022                                 c = SDL_MapRGB(surf_screen->format,0,255,255);
1023                         } else {
1024                                 c = heatcolor[(int)shieldlevel];
1025                                 shieldlevel-= movementrate;
1026                         }
1027
1028                         shieldpulse += 0.2;
1029                         for(p = black_point; p<blackptr; p ++ ) { 
1030                                 x = p->x + (int)xship + (rnd() + rnd()-1)*sin(shieldpulse)*4 + 1;
1031                                 y = p->y + (int)yship + (rnd() + rnd()-1)*sin(shieldpulse)*4 + 1;
1032                                 if(x>0 && y>0 && x<XSIZE && y<YSIZE) {
1033                                         offset = surf_screen->pitch/2 * y + x;
1034                                         raw_pixels[offset] = c;
1035                                 }
1036                         }
1037                 } else {
1038                         // When the shields are off, check that the black points 
1039                         // on the ship are still black, and not covered up by rocks
1040                         for(p = black_point; p<blackptr; p ++ ) { 
1041                                 offset = surf_screen->pitch/2 * (p->y + (int)yship) + p->x + (int)xship;
1042                                 if(raw_pixels[offset]) {
1043                                         // Set the bang flag
1044                                         bang = 1;
1045                                 }
1046                         }
1047                 }
1048                 SDL_UnlockSurface(surf_screen);
1049         }
1050
1051 #ifdef DOTCOLLISION
1052         dotcollision(surf_screen); // Kill dots that are not on their spots
1053 #endif
1054
1055         // Draw all the little ships
1056         if(state == GAMEPLAY || state == DEAD_PAUSE || state == GAME_OVER)
1057         for(i = 0; i<nships-1; i ++ ) {
1058                 src.w = surf_life->w;
1059                 src.h = surf_life->h;
1060                 dest.w = src.w;
1061                 dest.h = src.h;
1062                 dest.x = (i + 1)*(src.w + 10);
1063                 dest.y = 20;
1064                 SDL_BlitSurface(surf_life,&src,surf_screen,&dest);
1065         }
1066
1067
1068         // Update the score
1069         /*
1070         n = SDL_GetTicks()-initticks;
1071         if(score)
1072         ticks_since_last = n-score;
1073         score = n;
1074         */
1075
1076         ticks_since_last = SDL_GetTicks()-last_ticks;
1077         last_ticks = SDL_GetTicks();
1078         if(ticks_since_last>200 || ticks_since_last<0) {
1079                 movementrate = 0;
1080         }
1081         else {
1082                 movementrate = ticks_since_last/50.0;
1083                 if(state == GAMEPLAY) {
1084                         score += ticks_since_last;
1085                 }
1086         }
1087
1088         // Update the surface
1089         SDL_Flip(surf_screen);
1090
1091
1092         return bang;
1093 }
1094 int gameloop() {
1095         int i = 0;
1096         Uint8 *keystate;
1097
1098
1099         for(;;) {
1100                 if(!paused) {
1101                         // Count down the game loop timer, and change state when it gets to zero or less;
1102
1103                         if((state_timeout -= movementrate*3) < 0) {
1104                                 switch(state) {
1105                                         case DEAD_PAUSE:
1106                                                 // Create a new ship and start all over again
1107                                                 state = GAMEPLAY;
1108                                                 play_tune(1);
1109                                                 initialshield = 150;
1110                                                 xship = 10;
1111                                                 yship = YSIZE/2;
1112                                                 xvel = 2;
1113                                                 yvel = 0;
1114                                                 shieldlevel = 3*W;
1115                                         break;
1116                                         case GAME_OVER:
1117                                                 state = HIGH_SCORE_ENTRY;
1118                                                 clearBuffer();
1119                                                 name[0] = 0;
1120                                                 state_timeout = 5.0e6;
1121
1122                                                 if(score>= high[7].score) {
1123                                                         // Read the high score table from the storage file
1124                                                         read_high_score_table();
1125
1126                                                         // Find ranking of this score, store as scorerank
1127                                                         for(i = 0; i<8; i ++ ) {
1128                                                         if(high[i].score <= score) {
1129                                                                 scorerank = i;
1130                                                                 break;
1131                                                         }
1132                                                         }
1133
1134                                                         // Move all lower scores down a notch
1135                                                         for(i = 7; i>= scorerank; i--)
1136                                                         high[i] = high[i-1];
1137
1138                                                         // Insert blank high score
1139                                                         high[scorerank].score = score;
1140                                                         high[scorerank].name = "";
1141                                                         high[scorerank].allocated = 0;
1142                                                 }
1143
1144                                         break;
1145                                         case HIGH_SCORE_DISPLAY:
1146                                                 state = TITLE_PAGE;
1147                                                 state_timeout = 500.0;
1148                                         break;
1149                                         case HIGH_SCORE_ENTRY:
1150                                                 // state = TITLE_PAGE;
1151                                                 // play_tune(1);
1152                                                 // state_timeout = 100.0;
1153                                         break;
1154                                         case TITLE_PAGE:
1155                                                 state = HIGH_SCORE_DISPLAY;
1156                                                 state_timeout = 200.0;
1157                                         break;
1158                                 }
1159                         }
1160
1161                         if(--countdown<= 0 && (rnd()*100.0<(rockrate += 0.025))) {
1162                                 // Create a rock
1163                                 rockptr ++ ;
1164                                 if(rockptr-rock>= MAXROCKS) {
1165                                         rockptr = rock;
1166                                 }
1167                                 if(!rockptr->active) {
1168                                         rockptr->x = (float)XSIZE;
1169                                         rockptr->xvel = -(rockspeed)*(1 + rnd());
1170                                         rockptr->yvel = rnd()-0.5;
1171                                         rockptr->type_number = random() % NROCKS;
1172                                         rockptr->heat = 0;
1173                                         rockptr->image = surf_rock[rockptr->type_number];// [random()%NROCKS];
1174                                         rockptr->active = 1;
1175                                         rockptr->y = rnd()*(YSIZE + rockptr->image->h);
1176                                 }
1177                                 if(movementrate>0.1) {
1178                                         countdown = (int)(ROCKRATE/movementrate);
1179                                 } else {
1180                                         countdown = 0;
1181                                 }
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
1259                         if(keystate[SDLK_SPACE] && (state == HIGH_SCORE_DISPLAY || state == TITLE_PAGE || state == DEMO)) {
1260
1261                                 for(i = 0; i<MAXROCKS; i++ ) {
1262                                         rock[i].active = 0;
1263                                 }
1264
1265                                 rockrate = 54.0;
1266                                 rockspeed = 5.0;
1267
1268                                 nships = 4;
1269                                 score = 0;
1270
1271                                 state = GAMEPLAY;
1272                                 play_tune(1);
1273
1274                                 xvel = -1;
1275                                 gameover = 0;
1276                                 yvel = 0;
1277                                 xship = 0;
1278                                 yship = YSIZE/2;
1279                                 shieldlevel = 3*W;
1280                                 initialshield = 0;
1281
1282                         }
1283
1284                         maneuver = 0;
1285                         laser = 0;
1286                 } else {
1287                         SDL_PumpEvents();
1288                         keystate = SDL_GetKeyState(NULL);
1289                 }
1290
1291                 if(state == GAMEPLAY) {
1292                         if(!gameover) {
1293
1294                                 if(!paused) {
1295                                         if(keystate[SDLK_UP] | keystate[SDLK_c])                { yvel -= 1.5*movementrate; maneuver|= 1<<3;}
1296                                         if(keystate[SDLK_DOWN] | keystate[SDLK_t])              { yvel += 1.5*movementrate; maneuver|= 1<<1;}
1297                                         if(keystate[SDLK_LEFT] | keystate[SDLK_h])              { xvel -= 1.5*movementrate; maneuver|= 1<<2;}
1298                                         if(keystate[SDLK_RIGHT] | keystate[SDLK_n])             { xvel += 1.5*movementrate; maneuver|= 1;}
1299                                         if(keystate[SDLK_3])            { SDL_SaveBMP(surf_screen, "snapshot.bmp"); }
1300                                 }
1301
1302                                 if(keystate[SDLK_p] | keystate[SDLK_s]) {
1303                                         if(!pausedown) {
1304                                                 paused = !paused;
1305                                                 if(paused) {
1306                                                         SDL_Rect src,dest;
1307                                                         src.w = surf_b_variations->w;
1308                                                         src.h = surf_b_variations->h;
1309                                                         dest.w = src.w;
1310                                                         dest.h = src.h;
1311                                                         dest.x = (XSIZE-src.w)/2;
1312                                                         dest.y = (YSIZE-src.h)/2;
1313                                                         SDL_BlitSurface(surf_b_variations,&src,surf_screen,&dest);
1314                                                         // Update the surface
1315                                                         SDL_Flip(surf_screen);
1316                                                 }
1317                                                 pausedown = 1;
1318                                         }
1319                                 } else {
1320                                         pausedown = 0;
1321                                 }
1322
1323                         }
1324                         else {
1325                                 shieldsup = 0;
1326                                 paused = 0;
1327                                 pausedown = 0;
1328                         }
1329                 } else if(state == GAME_OVER) {
1330                         if(keystate[SDLK_SPACE]) {
1331                                 state_timeout = -1;
1332                         }
1333                 }
1334         }
1335 }
1336 main(int argc, char **argv) {
1337         int i, x, fullscreen;
1338
1339         fullscreen = 0;
1340         tail_plume = 0;
1341         friction = 0;
1342         oss_sound_flag = 1;
1343
1344         while ((x = getopt(argc,argv,"efhsp"))>= 0) {
1345                 switch(x) {
1346                         case 'e': // engine
1347                                 tail_plume = 1;
1348                         break;
1349                         case 'f': // fullscreen
1350                                 fullscreen = 1;
1351                         break;
1352                         case 'h': // help
1353                                 printf("Variations on RockDodger\n"
1354                                           " -e Big tail [E]ngine\n"
1355                                           " -f [F]ull screen\n"
1356                                           " -h This [H]elp message\n"
1357                                           " -p Stupid original [P]hysics (friction)\n"
1358                                           " -s [S]ilent (no sound)\n");
1359                                 exit(0);
1360                         break;
1361                         case 'p': // physics
1362                                 friction = 1;
1363                         break;
1364                         case 's': // silent
1365                                 oss_sound_flag = 0;
1366                         break;
1367                 }
1368         }
1369
1370         if(init(fullscreen)) {
1371                 printf ("ta: '%s'\n",initerror);
1372                 return 1;
1373         }
1374
1375         while(1) {
1376                 for(i = 0; i<MAXROCKS; i ++ ) {
1377                         rock[i].active = 0;
1378                 }
1379                 rockrate = 54.0;
1380                 rockspeed = 5.0;
1381                 initticks = SDL_GetTicks();
1382                 if(gameloop() == 0) {
1383                         break;
1384                 }
1385                 printf ("score = %d\n",score);
1386                 SDL_Delay(1000);
1387         }
1388
1389         return 0;
1390 }