JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
no starting shields ever
[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 #define STARTSPACE 430 // pixels from the left which will be cleared of rocks when you die
57 // }}}
58 // macros {{{
59 #define CONDERROR(a) if((a)) {initerror = strdup(SDL_GetError());return 1;}
60 #define NULLERROR(a) CONDERROR((a) == NULL)
61 // }}}
62
63 // ************************************* STRUCTS
64 struct rock_struct {
65         // Array of black pixel coordinates. This is scanned 
66         // every frame to see if it's still black, and as
67         // soon as it isn't we BLOW UP
68         float x,y,xvel,yvel;
69         int active;
70         SDL_Surface *image;
71         int type_number;
72         float heat;
73 }; 
74 struct black_point_struct {
75         int x,y;
76 };
77 struct bangdots {
78         // Bang dots have the same colour as shield dots.
79         // Bang dots get darker as they age.
80         // Some are coloured the same as the ex-ship.
81         float x,y,dx,dy;
82         Uint16 c; // when zero, use heatcolor[bangdotlife]
83         float life;     // When reduced to 0, set active = 0
84         int active;
85         float decay;// Amount by which to reduce life each time dot is drawn
86 };
87 struct enginedots {
88         // Engine dots stream out the back of the ship, getting darker as they go.
89         int active;
90         float x,y,dx,dy;
91         // The life of an engine dot 
92         // is a number starting at between 0 and 50 and counting backward.
93         float life;     // When reduced to 0, set active = 0
94 };
95 struct spacedot {
96         // Space dots are harmless background items
97         // All are active. When one falls off the edge, another is created at the start.
98         float x,y,dx;
99         Uint16 color;
100 };
101 // High score table {{{
102 struct highscore {
103         int score;
104         char *name;
105         int allocated;
106 } high[] = {
107         {13000,"Pad",0},
108         {12500,"Pad",0},
109         {6500,"Pad",0},
110         {5000,"Pad",0},
111         {3000,"Pad",0},
112         {2500,"Pad",0},
113         {2000,"Pad",0},
114         {1500,"Pad",0}
115 };
116 // }}}
117
118 // ************************************* VARS
119 // SDL_Surface global variables {{{
120 SDL_Surface 
121         *surf_screen,   // Screen
122         *surf_b_variations, // "variations" banner
123         *surf_b_on, // "on" banner
124         *surf_b_rockdodger, // "rockdodger" banner
125         *surf_b_game,   // Title element "game"
126         *surf_b_over,   // Title element "over"
127         *surf_ship,             // Spaceship element
128         *surf_life,     // Indicator of number of ships remaining
129         *surf_rock[NROCKS],     // THE ROCKS
130         *surf_deadrock[NROCKS], // THE DEAD ROCKS
131         *surf_font_big; // The big font
132 // }}}
133 // Structure global variables {{{
134 struct enginedots edot[MAXENGINEDOTS], *dotptr = edot;
135 struct rock_struct rock[MAXROCKS], *rockptr = rock;
136 struct black_point_struct black_point[MAXBLACKPOINTS], *blackptr = black_point;
137 struct bangdots bdot[MAXBANGDOTS], *bdotptr = bdot;
138 struct spacedot sdot[MAXSPACEDOTS];
139 // }}}
140 // Other global variables {{{
141 char topline[1024];
142 char *initerror = "";
143 char name[1024], debug1[1024];
144
145 float xship,yship = 240.0;      // X position, 0..XSIZE
146 float xvel,yvel;        // Change in X position per tick.
147 float rockrate,rockspeed;
148 float movementrate;
149 float shieldlevel, shieldpulse = 0;
150 float yscroll;
151
152 int nships,score,initticks,ticks_since_last, last_ticks;
153 int initialshield, gameover, fast;
154 int countdown = 0;
155 int maneuver = 0;
156 int laser = 0;
157 int shieldsup = 0;
158 int oss_sound_flag = 0;
159 int tail_plume = 0; // display big engine at the back?
160 int friction = 0;       // should there be friction?
161 int scorerank;
162 float fadetimer = 0,faderate;
163
164 int pausedown = 0,paused = 0;
165
166 // bangdot start (bd1) and end (bd2) position:
167 int bd1 = 0, bd2 = 0;
168
169 int xoffset[NROCKS][MAXROCKHEIGHT];
170
171 enum states {
172         TITLE_PAGE,
173         GAMEPLAY,
174         DEAD_PAUSE,
175         GAME_OVER,
176         HIGH_SCORE_ENTRY,
177         HIGH_SCORE_DISPLAY,
178         DEMO
179 };
180 enum states state = TITLE_PAGE;
181 float state_timeout = 600.0;
182
183 const int fakesin[] = {0,1,0,-1};
184 const int fakecos[] = {1,0,-1,0};
185 #define NSEQUENCE 2
186 char *sequence[] = {
187         "Press SPACE to start",
188         "http://qualdan.com/vor/"
189 };
190
191 int bangdotlife, nbangdots;
192 Uint16 heatcolor[W*3];
193
194 char *data_dir;
195 extern char *optarg;
196 extern int optind, opterr, optopt;
197 // }}}
198
199 // ************************************* FUNCS
200 #ifdef DOTCOLLISION
201 int dotcollision(SDL_Surface *s) {
202         int i,j,m;
203         Uint16 *rawpixel, *r;
204
205         /*
206          * Kill all the dots which collide with other objects.
207          * This does not work, it's probably in the wrong place or something.
208          */
209         SDL_LockSurface(s);
210         rawpixel = (Uint16 *) s->pixels;
211         if(bangdotlife > 0 && bangdotlife<80) {
212                 for(i = 0; i<nbangdots; i++) {
213                         if(bdot[i].x>0 && bdot[i].x<XSIZE && bdot[i].y>0 && bdot[i].y<YSIZE) {
214                                 r = &rawpixel[(int)(s->pitch/2*(int)(bdot[i].y)) + (int)(bdot[i].x)];
215                         if(*r != (bdot[i].c ? bdot[i].c : heatcolor[bangdotlife*2]))
216                                 bdot[i].active = 0;
217                         }
218                 }
219         }
220         SDL_UnlockSurface(s);
221
222         return;
223 }
224 #endif
225
226 FILE *hs_fopen(char *mode) {
227         FILE *f;
228         mode_t mask;
229         mask = umask(0111);
230         if(f = fopen("/usr/share/vor/.highscore",mode)) {
231                 umask(mask);
232                 return f;
233         }
234         else {
235                 char s[1024];
236                 umask(0177);
237                 sprintf(s,"%s/.vor-high",getenv("HOME"));
238                 if(f = fopen(s,mode)) {
239                         umask(mask);
240                         return f;
241                 }
242                 else {
243                         umask(mask);
244                         return 0;
245                 }
246         }
247 }
248 void read_high_score_table() {
249         FILE *f;
250         int i;
251         if(f = hs_fopen("r")) {
252                 // If the file exists, read from it
253                 for(i = 0; i<8; i++) {
254                         char s[1024];
255                         int highscore;
256                         if(fscanf (f, "%d %[^\n]", &highscore, s) != 2) {
257                                 break;
258                         }
259                         if(high[i].allocated) {
260                                 free(high[i].name);
261                         }
262                         high[i].name = strdup(s);
263                         high[i].score = highscore;
264                         high[i].allocated = 1;
265                 }
266                 fclose(f);
267         }
268 }
269 void write_high_score_table() {
270         FILE *f;
271         int i;
272         if(f = hs_fopen("w")) {
273                 // If the file exists, write to it
274                 for(i = 0; i<8; i++) {
275                         fprintf (f, "%d %s\n", high[i].score, high[i].name);
276                 }
277                 fclose(f);
278         }
279 }
280 void snprintscore(char *s, size_t n, int score) {
281         int min = score/60000;
282         int sec = score/1000%60;
283         int tenths = score%1000/100;
284         if(min) {
285                 snprintf(s, n, "%2d:%.2d.%d", min, sec, tenths);
286         } else {
287                 snprintf(s, n, " %2d.%d", sec, tenths);
288         }
289 }
290 float rnd() {
291         return (float)random()/(float)RAND_MAX;
292 }
293 void init_engine_dots() {
294         int i;
295         for(i = 0; i<MAXENGINEDOTS; i++) {
296                 edot[i].active = 0;
297         }
298 }
299 void init_space_dots() {
300         int i,intensity;
301         for(i = 0; i<MAXSPACEDOTS; i++) {
302                 float r;
303
304                 sdot[i].x = rnd()*(XSIZE-5);
305                 sdot[i].y = rnd()*(YSIZE-5);
306
307                 r = rnd()*rnd();
308
309                 sdot[i].dx = -r*4;
310                 // -1/((1-r) + .3);
311                 intensity = (int)(r*180 + 70);
312                 sdot[i].color = SDL_MapRGB(surf_screen->format,intensity,intensity,intensity);
313
314         }
315 }
316
317 int drawlaser() {
318         int i,xc,hitrock;
319         Uint16 c, *rawpixel;
320
321         hitrock = -1;
322         xc = XSIZE;
323         // let xc = x coordinate of the collision between the laser and a space rock
324         // 1. Calculate xc and determine the asteroid that was hit
325         for(i = 0; i<MAXROCKS; i++) {
326                 if(rock[i].active) {
327                         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) {
328                                 xc = rock[i].x + (rock[i].image->w/2);
329                                 hitrock = i;
330                         }
331                 }
332         }
333
334         if(hitrock >= 0) {
335                 rock[hitrock].heat += movementrate*3;
336         }
337
338         // Plot a number of random dots between xship and XSIZE
339         SDL_LockSurface(surf_screen);
340         rawpixel = (Uint16 *) surf_screen->pixels;
341         c = SDL_MapRGB(surf_ship->format,rnd()*128,128 + rnd()*120,rnd()*128);
342
343         for(i = 0; i<(xc-xship)*5; i += 10) {
344                 int x,y;
345                 x = rnd()*(xc-(xship + 32)) + xship + 32;
346                 y = yship + 12 + (rnd()-0.5)*1.5;
347                 rawpixel[surf_screen->pitch/2*y + x] = c;
348         }
349
350         SDL_UnlockSurface(surf_screen);
351 }
352
353
354 int makebangdots(int xbang, int ybang, int xvel, int yvel, SDL_Surface *s, int power) {
355
356         // TODO - stop generating dots after a certain amount of time has passed, to cope with slower CPUs.
357         // TODO - generate and display dots in a circular buffer
358
359         int i,x,y,n,endcount;
360         Uint16 *rawpixel,c;
361         double theta,r,dx,dy;
362         int begin_generate;
363
364         begin_generate = SDL_GetTicks();
365
366         SDL_LockSurface(s);
367         rawpixel = (Uint16 *) s->pixels;
368
369         //for(n = 0; n <= power/2; n++) {
370
371         endcount = 0;
372         while (endcount<3) {
373
374         for(x = 0; x<s->w; x++) {
375                 for(y = 0; y<s->h; y++) {
376                         c = rawpixel[s->pitch/2*y + x];
377                         if(c && c != SDL_MapRGB(s->format,0,255,0)) {
378
379                                 theta = rnd()*M_PI*2;
380
381                                 r = 1-(rnd()*rnd());
382
383                                 bdot[bd2].dx = (power/50.0)*45.0*cos(theta)*r + xvel;
384                                 bdot[bd2].dy = (power/50.0)*45.0*sin(theta)*r + yvel;
385                                 bdot[bd2].x = x + xbang;
386                                 bdot[bd2].y = y + ybang;
387
388                                 // Replace the last few bang dots with the pixels from the exploding object
389                                 bdot[bd2].c = (endcount>0)?c:0;
390                                 bdot[bd2].life = 100;
391                                 bdot[bd2].decay = rnd()*3 + 1;
392                                 bdot[bd2].active = 1;
393
394                                 bd2++;
395                                 bd2 %= MAXBANGDOTS;
396
397                                 // If the circular buffer is filled, who cares? They've had their chance.
398                                 //if(bd2 == bd1-1) goto exitloop;
399
400                         }
401                 }
402         }
403
404         if(SDL_GetTicks() - begin_generate > 7) endcount++;
405
406         }
407 exitloop:
408
409         SDL_UnlockSurface(s);
410
411 }
412
413 void draw_bang_dots(SDL_Surface *s) {
414         int i;
415         int first_i, last_i;
416         Uint16 *rawpixel;
417         rawpixel = (Uint16 *) s->pixels;
418
419         first_i = -1;
420
421         for(i = bd1; (bd1 <= bd2)?(i<bd2):(i >= bd1 && i < bd2); last_i = ++i) {
422
423                 i %= MAXBANGDOTS;
424
425                 if(bdot[i].x <= 0 || bdot[i].x >= XSIZE || bdot[i].y <= 0 || bdot[i].y >= YSIZE) {
426                         // If the dot has drifted outside the perimeter, kill it
427                         bdot[i].active = 0;
428                 }
429
430                 if(bdot[i].active) {
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)] = bdot[i].c ? bdot[i].c : heatcolor[(int)(bdot[i].life*3)];
435                         bdot[i].life -= bdot[i].decay;
436                         bdot[i].x += bdot[i].dx*movementrate;
437                         bdot[i].y += bdot[i].dy*movementrate + yscroll;
438
439                         if(bdot[i].life<0)
440                         bdot[i].active = 0;
441                 }
442         }
443
444         if(first_i >= 0) {
445                 bd1 = first_i;
446                 bd2 = last_i;
447         }
448         else {
449                 bd1 = 0;
450                 bd2 = 0;
451         }
452
453 }
454
455
456 void draw_space_dots(SDL_Surface *s) {
457         int i;
458         Uint16 *rawpixel;
459         rawpixel = (Uint16 *) s->pixels;
460
461         for(i = 0; i<MAXSPACEDOTS; i++) {
462                 if(sdot[i].y<0) {
463                         sdot[i].y = 0;
464                 }
465                 rawpixel[(int)(s->pitch/2*(int)sdot[i].y) + (int)(sdot[i].x)] = sdot[i].color;
466                 sdot[i].x += sdot[i].dx*movementrate;
467                 sdot[i].y += yscroll;
468                 if(sdot[i].y > YSIZE) {
469                         sdot[i].y -= YSIZE;
470                 } else if(sdot[i].y < 0) {
471                         sdot[i].y += YSIZE;
472                 }
473                 if(sdot[i].x<0) {
474                         sdot[i].x = XSIZE;
475                 }
476         }
477 }
478
479 void draw_engine_dots(SDL_Surface *s) {
480         int i;
481         Uint16 *rawpixel;
482         rawpixel = (Uint16 *) s->pixels;
483
484         for(i = 0; i<MAXENGINEDOTS; i++) {
485                 if(edot[i].active) {
486                         edot[i].x += edot[i].dx*movementrate;
487                         edot[i].y += edot[i].dy*movementrate + yscroll;
488                         if((edot[i].life -= movementrate*3)<0 || edot[i].y<0 || edot[i].y>YSIZE) {
489                                 edot[i].active = 0;
490                         } else if(edot[i].x<0 || edot[i].x>XSIZE) {
491                                 edot[i].active = 0;
492                         } else {
493                                 int heatindex;
494                                 heatindex = edot[i].life * 6;
495                                 //rawpixel[(int)(s->pitch/2*(int)(edot[i].y)) + (int)(edot[i].x)] = lifecolor[(int)(edot[i].life)];
496                                 rawpixel[(int)(s->pitch/2*(int)(edot[i].y)) + (int)(edot[i].x)] = heatindex>3*W ? heatcolor[3*W-1] : heatcolor[heatindex];
497                         }
498                 }
499         }
500 }
501
502 void create_engine_dots(int newdots) {
503         int i;
504         double theta,r,dx,dy;
505
506         if(!tail_plume) return;
507
508         if(state == GAMEPLAY) {
509                 for(i = 0; i<newdots*movementrate; i++) {
510                         if(dotptr->active == 0) {
511                                 theta = rnd()*M_PI*2;
512                                 r = rnd();
513                                 dx = cos(theta)*r;
514                                 dy = sin(theta)*r;
515
516                                 dotptr->active = 1;
517                                 dotptr->x = xship + surf_ship->w/2-14;
518                                 dotptr->y = yship + surf_ship->h/2 + (rnd()-0.5)*5-1;
519                                 dotptr->dx = 10*(dx-1.5) + xvel;
520                                 dotptr->dy = 1*dy + yvel;
521                                 dotptr->life = 45 + rnd(1)*5;
522
523                                 dotptr++;
524                                 if(dotptr-edot >= MAXENGINEDOTS) {
525                                         dotptr = edot;
526                                 }
527                         }
528                 }
529         }
530 }
531
532 void create_engine_dots2(int newdots, int m) {
533         int i;
534         double theta, theta2, dx, dy, adx, ady;
535
536         // Don't create fresh engine dots when
537         // the game is not being played and a demo is not beng shown
538         if(state != GAMEPLAY && state != DEMO) return;
539
540         for(i = 0; i<newdots; i++) {
541                 if(dotptr->active == 0) {
542                         theta = rnd()*M_PI*2;
543                         theta2 = rnd()*M_PI*2;
544
545                         dx = cos(theta) * fabs(cos(theta2));
546                         dy = sin(theta) * fabs(cos(theta2));
547                         adx = fabs(dx);
548                         ady = fabs(dy);
549
550
551                         dotptr->active = 1;
552                         dotptr->x = xship + surf_ship->w/2 + (rnd()-0.5)*3;
553                         dotptr->y = yship + surf_ship->h/2 + (rnd()-0.5)*3;
554
555                         switch(m) {
556                                 case 0:
557                                         dotptr->x -= 14;
558                                         dotptr->dx = -20*adx + xvel;
559                                         dotptr->dy = 2*dy + yvel;
560                                         dotptr->life = 60 * adx;
561                                 break;
562                                 case 1:
563                                         dotptr->dx = 2*dx + xvel;
564                                         dotptr->dy = -20*ady + yvel;
565                                         dotptr->life = 60 * ady;
566                                 break;
567                                 case 2:
568                                         dotptr->x += 14;
569                                         dotptr->dx = 20*adx + xvel;
570                                         dotptr->dy = 2*dy + yvel;
571                                         dotptr->life = 60 * adx;
572                                 break;
573                                 case 3:
574                                         dotptr->dx = 2*dx + xvel;
575                                         dotptr->dy = 20*ady + yvel;
576                                         dotptr->life = 60 * ady;
577                                 break;
578                         }
579                         dotptr++;
580                         if(dotptr-edot >= MAXENGINEDOTS) {
581                                 dotptr = edot;
582                         }
583                 }
584         }
585 }
586
587 int drawdots(SDL_Surface *s) {
588         int m, scorepos, n;
589
590         SDL_LockSurface(s);
591         // Draw the background stars aka space dots
592         draw_space_dots(s);
593
594         // Draw the score when playing the game or whn the game is freshly over
595         if(1 || state == GAMEPLAY || state == DEAD_PAUSE || state == GAME_OVER ) {
596                 SDL_UnlockSurface(s);
597
598                 scorepos = XSIZE-250;
599                 n = snprintf(topline, 50, "Time: ");
600                 snprintscore(topline + n, 50-n, score);
601                 PutString(s,scorepos,0,topline);
602
603                 SDL_LockSurface(s);
604         }
605
606         // Draw all the engine dots
607         draw_engine_dots(s);
608
609         // Create more engine dots comin out da back
610         if(!gameover)
611         create_engine_dots(200);
612
613         // Create engine dots out the side we're moving from
614         for(m = 0; m<4; m++) {
615                 if(maneuver & 1<<m) { // 'maneuver' is a bit field
616                         create_engine_dots2(80,m);
617                 }
618         }
619
620         // Draw all outstanding bang dots
621         //if(bangdotlife-- > 0) 
622         draw_bang_dots(s);
623
624         SDL_UnlockSurface(s);
625 }
626
627 char * load_file(char *s) {
628         static char retval[1024];
629         snprintf(retval, 1024, "%s/%s", data_dir, s);
630         return retval;
631 }
632
633
634 int missing(char *dirname) {
635         struct stat buf;
636         stat(dirname, &buf);
637         return (!S_ISDIR(buf.st_mode));
638 }
639
640 int init(int fullscreen) {
641
642         int i,j;
643         SDL_Surface *temp;
644         Uint16 *raw_pixels;
645         Uint32 flag;
646
647         read_high_score_table();
648
649         // Where are our data files?
650         // default: ./data
651         // second alternative: RD_DATADIR
652         // final alternative: /usr/share/vor
653         data_dir = strdup("./data");
654         if(missing(data_dir)) {
655                 char *env;
656                 env = getenv("RD_DATADIR");
657                 if(env != NULL) {
658                         data_dir = strdup(env);
659                         if(missing(data_dir)) {
660                                 fprintf (stderr,"Cannot find data directory $RD_DATADIR\n");
661                                 exit(-1);
662                         }
663                 } else {
664                         data_dir = strdup("/usr/share/vor");
665                         if(missing(data_dir)) {
666                                 fprintf (stderr,"Cannot find data in %s\n", data_dir);
667                                 exit(-2);
668                         }
669                 }
670         }
671
672         if(oss_sound_flag) {
673
674         // Initialise SDL with audio and video
675         if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
676                 oss_sound_flag = 0;
677                 printf ("Can't open sound, starting without it\n");
678                 atexit(SDL_Quit);
679         } else {
680                 atexit(SDL_Quit);
681                 atexit(SDL_CloseAudio);
682                 oss_sound_flag = init_sound();
683         }
684
685         } else {
686                 // Initialise with video only
687                 CONDERROR(SDL_Init(SDL_INIT_VIDEO) != 0);
688                 atexit(SDL_Quit);
689         }
690
691         if(oss_sound_flag)
692         play_tune(0);
693
694         // Attempt to get the required video size
695         flag = SDL_DOUBLEBUF | SDL_HWSURFACE;
696         if(fullscreen) flag |= SDL_FULLSCREEN;
697         surf_screen = SDL_SetVideoMode(XSIZE,YSIZE,16,flag);
698
699         // Set the title bar text
700         SDL_WM_SetCaption("Rock Dodgers", "rockdodgers");
701
702         NULLERROR(surf_screen);
703
704         // Set the heat color from the range 0 (cold) to 300 (blue-white)
705         for(i = 0; i<W*3; i++) {
706                 heatcolor[i] = SDL_MapRGB(
707                         surf_screen->format,
708                         (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?
709                 );
710         }
711
712         // Load the banners
713         NULLERROR(temp = IMG_Load(load_file("banners/variations.png")));
714         NULLERROR(surf_b_variations = SDL_DisplayFormat(temp));
715
716         NULLERROR(temp = IMG_Load(load_file("banners/on.png")));
717         NULLERROR(surf_b_on = SDL_DisplayFormat(temp));
718
719         NULLERROR(temp = IMG_Load(load_file("banners/rockdodger.png")));
720         NULLERROR(surf_b_rockdodger = SDL_DisplayFormat(temp));
721
722         NULLERROR(temp = IMG_Load(load_file("banners/game.png")));
723         NULLERROR(surf_b_game = SDL_DisplayFormat(temp));
724
725         NULLERROR(temp = IMG_Load(load_file("banners/over.png")));
726         NULLERROR(surf_b_over = SDL_DisplayFormat(temp));
727
728         surf_font_big = IMG_Load(load_file(BIG_FONT_FILE));
729         InitFont(surf_font_big);
730
731         // Load the spaceship graphic.
732         NULLERROR(temp = IMG_Load(load_file("sprites/ship.png")));
733         NULLERROR(surf_ship = SDL_DisplayFormat(temp));
734
735         // Load the life indicator (small ship) graphic.
736         NULLERROR(temp = IMG_Load(load_file("indicators/life.png")));
737         NULLERROR(surf_life = SDL_DisplayFormat(temp));
738
739         // Create the array of black points;
740         SDL_LockSurface(surf_ship);
741         raw_pixels = (Uint16 *) surf_ship->pixels;
742         for(i = 0; i<surf_ship->w; i++) {
743                 for(j = 0; j<surf_ship->h; j++) {
744                         if(raw_pixels[j*(surf_ship->pitch)/2 + i] == 0) {
745                                 blackptr->x = i;
746                                 blackptr->y = j;
747                                 blackptr++;
748                         }
749                 }
750         }
751
752         SDL_UnlockSurface(surf_ship);
753
754         init_engine_dots();
755         init_space_dots();
756
757         // Load all our lovely rocks
758         for(i = 0; i<NROCKS; i++) {
759                 char a[100];
760
761                 sprintf(a,load_file("sprites/rock%d.png"),i);
762                 NULLERROR(temp = IMG_Load(a));
763                 NULLERROR(surf_rock[i] = SDL_DisplayFormat(temp));
764
765                 sprintf(a,load_file("sprites/deadrock%d.png"),i);
766                 NULLERROR(temp = IMG_Load(a));
767                 NULLERROR(surf_deadrock[i] = SDL_DisplayFormat(temp));
768         }
769
770         // Remove the mouse cursor
771 #ifdef SDL_DISABLE
772         SDL_ShowCursor(SDL_DISABLE);
773 #endif
774
775         return 0;
776 }
777 int draw() {
778         int i,n;
779         SDL_Rect src,dest;
780         struct black_point_struct *p;
781         Uint16 *raw_pixels;
782         int bang, offset, x;
783         char *text;
784         float fadegame,fadeover;
785
786         char *statedisplay, buf[1024];
787         
788         bang = 0;
789
790         src.x = 0;
791         src.y = 0;
792         dest.x = 0;
793         dest.y = 0;
794
795         // Draw a fully black background
796         SDL_FillRect(surf_screen,NULL,0);
797
798
799 #ifdef DEBUG
800         // DEBUG {{{
801         // Show the current state
802         switch (state) {
803                 case TITLE_PAGE:
804                         statedisplay = "title_page";
805                 break;
806                 case GAMEPLAY:
807                         statedisplay = "gameplay";
808                 break;
809                 case DEAD_PAUSE:
810                         statedisplay = "dead_pause";
811                 break;
812                 case GAME_OVER:
813                         statedisplay = "game_over";
814                 break;
815                 case HIGH_SCORE_ENTRY:
816                         statedisplay = "high_score_entry";
817                 break;
818                 case HIGH_SCORE_DISPLAY:
819                         statedisplay = "high_score_display";
820                 break;
821                 case DEMO:
822                         statedisplay = "demo";
823                 break;
824         }
825         snprintf(buf,1024, "mode = %s", statedisplay);
826         PutString(surf_screen,0,YSIZE-50,buf);
827         // }}}
828 #endif
829         
830         // Draw the background dots
831         drawdots(surf_screen);
832
833         // If it's firing, draw the laser
834         if(laser) {
835                 drawlaser();
836         }
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) {
872                                         rock[i].heat -= movementrate;
873                                 }
874                         }
875
876                         // If the rock is heated past a certain point, the water content of
877                         // the rock flashes to steam, releasing enough energy to destroy
878                         // the rock in spectacular fashion.
879                         if(rock[i].heat>rock[i].image->h) {
880                                 rock[i].active = 0;
881                                 play_sound(1 + (int)(rnd()*3));
882                                 makebangdots(rock[i].x,rock[i].y,rock[i].xvel,rock[i].yvel,rock[i].image,10);
883                         }
884
885                 }
886         }
887
888         // If it's game over, show the game over graphic in the dead centre
889         switch (state) {
890                 case GAME_OVER:
891                         if(fadetimer<3.0/faderate) {
892                                 fadegame = fadetimer/(3.0/faderate);
893                         } else {
894                                 fadegame = 1.0;
895                         }
896
897                         if(fadetimer<3.0/faderate) {
898                                 fadeover = 0.0;
899                         } else if(fadetimer<6.0/faderate) {
900                                 fadeover = ((3.0/faderate)-fadetimer)/(6.0/faderate);
901                         } else {
902                                 fadeover = 1.0;
903                         }
904
905                         src.w = surf_b_game->w;
906                         src.h = surf_b_game->h;
907                         dest.w = src.w;
908                         dest.h = src.h;
909                         dest.x = (XSIZE-src.w)/2;
910                         dest.y = (YSIZE-src.h)/2-40;
911                         SDL_SetAlpha(surf_b_game, SDL_SRCALPHA, (int)(fadegame*(200 + 55*cos(fadetimer += movementrate/1.0))));
912                         SDL_BlitSurface(surf_b_game,&src,surf_screen,&dest);
913
914                         src.w = surf_b_over->w;
915                         src.h = surf_b_over->h;
916                         dest.w = src.w;
917                         dest.h = src.h;
918                         dest.x = (XSIZE-src.w)/2;
919                         dest.y = (YSIZE-src.h)/2 + 40;
920                         SDL_SetAlpha(surf_b_over, SDL_SRCALPHA, (int)(fadeover*(200 + 55*sin(fadetimer))));
921                         SDL_BlitSurface(surf_b_over,&src,surf_screen,&dest);
922                 break;
923
924                 case TITLE_PAGE:
925
926                         src.w = surf_b_variations->w;
927                         src.h = surf_b_variations->h;
928                         dest.w = src.w;
929                         dest.h = src.h;
930                         dest.x = (XSIZE-src.w)/2 + cos(fadetimer/6.5)*10;
931                         dest.y = (YSIZE/2-src.h)/2 + sin(fadetimer/5.0)*10;
932                         SDL_SetAlpha(surf_b_variations, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer += movementrate/2.0)));
933                         SDL_BlitSurface(surf_b_variations,&src,surf_screen,&dest);
934
935                         src.w = surf_b_on->w;
936                         src.h = surf_b_on->h;
937                         dest.w = src.w;
938                         dest.h = src.h;
939                         dest.x = (XSIZE-src.w)/2 + cos((fadetimer + 1.0)/6.5)*10;
940                         dest.y = (YSIZE/2-src.h)/2 + surf_b_variations->h + 20 + sin((fadetimer + 1.0)/5.0)*10;
941                         SDL_SetAlpha(surf_b_on, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer-1.0)));
942                         SDL_BlitSurface(surf_b_on,&src,surf_screen,&dest);
943
944                         src.w = surf_b_rockdodger->w;
945                         src.h = surf_b_rockdodger->h;
946                         dest.w = src.w;
947                         dest.h = src.h;
948                         dest.x = (XSIZE-src.w)/2 + cos((fadetimer + 2.0)/6.5)*10;
949                         dest.y = (YSIZE/2-src.h)/2 + surf_b_variations->h + surf_b_on->h + 40 + sin((fadetimer + 2.0)/5)*10;
950                         SDL_SetAlpha(surf_b_rockdodger, SDL_SRCALPHA, (int)(200 + 55*sin(fadetimer-2.0)));
951                         SDL_BlitSurface(surf_b_rockdodger,&src,surf_screen,&dest);
952
953                         text = "Version " VERSION;
954                         x = (XSIZE-SFont_wide(text))/2 + sin(fadetimer/4.5)*10;
955                         PutString(surf_screen,x,YSIZE-50 + sin(fadetimer/2)*5,text);
956
957                         text = sequence[(int)(fadetimer/40)%NSEQUENCE];
958                         //text = "Press SPACE to start!";
959                         x = (XSIZE-SFont_wide(text))/2 + cos(fadetimer/4.5)*10;
960                         PutString(surf_screen,x,YSIZE-100 + cos(fadetimer/3)*5,text);
961                 break;
962
963                 case HIGH_SCORE_ENTRY:
964
965                         if(score >= high[7].score) {
966                                 play_tune(2);
967                                 if(SFont_Input (surf_screen, 330, 50 + (scorerank + 2)*font_height, 300, name)) {
968                                         // Insert name into high score table
969
970                                         // Lose the lowest name forever (loser!)
971                                         //if(high[7].allocated)
972                                         //      free(high[7].name);                     // THIS WAS CRASHING SO I REMOVED IT
973
974                                         // Insert new high score
975                                         high[scorerank].score = score;
976                                         high[scorerank].name = strdup(name);    // MEMORY NEVER FREED!
977                                         high[scorerank].allocated = 1;
978                         
979                                         // Set the global name string to "", ready for the next winner
980                                         name[0] = 0;
981                         
982                                         // Change state to briefly show high scores page
983                                         state = HIGH_SCORE_DISPLAY;
984                                         state_timeout = 200;
985
986                                         // Write the high score table to the file
987                                         write_high_score_table();
988                         
989                                         // Play the title page tune
990                                         play_tune(0);
991                                 }
992                         } else {
993                                 state = HIGH_SCORE_DISPLAY;
994                                 state_timeout = 400;
995                         }
996                 // FALL THROUGH
997
998                 case HIGH_SCORE_DISPLAY:
999                         // Display de list o high scores mon.
1000                         PutString(surf_screen,180,50,"High scores");
1001                         for(i = 0; i<8; i++) {
1002                                 char s[1024];
1003                                 sprintf(s, "#%1d",i + 1);
1004                                 PutString(surf_screen, 150, 50 + (i + 2)*font_height,s);
1005                                 snprintscore(s, 1024, high[i].score);
1006                                 PutString(surf_screen, 200, 50 + (i + 2)*font_height,s);
1007                                 sprintf(s, "%3s", high[i].name);
1008                                 PutString(surf_screen, 330, 50 + (i + 2)*font_height,s);
1009                         }
1010
1011         }
1012
1013         if(!gameover && state == GAMEPLAY) {
1014                 // Show the freaky shields
1015                 SDL_LockSurface(surf_screen);
1016                 raw_pixels = (Uint16 *) surf_screen->pixels;
1017                 if(initialshield>0 || shieldsup && shieldlevel>0) {
1018                         int x,y,l;
1019                         Uint16 c;
1020
1021                         if(initialshield>0) {
1022                                 initialshield -= movementrate;
1023                                 c = SDL_MapRGB(surf_screen->format,0,255,255);
1024                         } else {
1025                                 c = heatcolor[(int)shieldlevel];
1026                                 shieldlevel -= movementrate;
1027                         }
1028
1029                         shieldpulse += 0.2;
1030                         for(p = black_point; p<blackptr; p++) { 
1031                                 x = p->x + (int)xship + (rnd() + rnd()-1)*sin(shieldpulse)*4 + 1;
1032                                 y = p->y + (int)yship + (rnd() + rnd()-1)*sin(shieldpulse)*4 + 1;
1033                                 if(x>0 && y>0 && x<XSIZE && y<YSIZE) {
1034                                         offset = surf_screen->pitch/2 * y + x;
1035                                         raw_pixels[offset] = c;
1036                                 }
1037                         }
1038                 } else {
1039                         // When the shields are off, check that the black points 
1040                         // on the ship are still black, and not covered up by rocks
1041                         for(p = black_point; p<blackptr; p++) { 
1042                                 offset = surf_screen->pitch/2 * (p->y + (int)yship) + p->x + (int)xship;
1043                                 if(raw_pixels[offset]) {
1044                                         // Set the bang flag
1045                                         bang = 1;
1046                                 }
1047                         }
1048                 }
1049                 SDL_UnlockSurface(surf_screen);
1050         }
1051
1052 #ifdef DOTCOLLISION
1053         dotcollision(surf_screen); // Kill dots that are not on their spots
1054 #endif
1055
1056         // Draw all the little ships
1057         if(state == GAMEPLAY || state == DEAD_PAUSE || state == GAME_OVER)
1058         for(i = 0; i<nships-1; i++) {
1059                 src.w = surf_life->w;
1060                 src.h = surf_life->h;
1061                 dest.w = src.w;
1062                 dest.h = src.h;
1063                 dest.x = (i + 1)*(src.w + 10);
1064                 dest.y = 20;
1065                 SDL_BlitSurface(surf_life,&src,surf_screen,&dest);
1066         }
1067
1068
1069         // Update the score
1070         /*
1071         n = SDL_GetTicks()-initticks;
1072         if(score)
1073         ticks_since_last = n-score;
1074         score = n;
1075         */
1076
1077         ticks_since_last = SDL_GetTicks()-last_ticks;
1078         last_ticks = SDL_GetTicks();
1079         if(ticks_since_last>200 || ticks_since_last<0) {
1080                 movementrate = 0;
1081         }
1082         else {
1083                 movementrate = ticks_since_last/50.0;
1084                 if(state == GAMEPLAY) {
1085                         score += ticks_since_last;
1086                 }
1087         }
1088
1089         // Update the surface
1090         SDL_Flip(surf_screen);
1091
1092
1093         return bang;
1094 }
1095 int gameloop() {
1096         int i = 0;
1097         Uint8 *keystate;
1098
1099
1100         for(;;) {
1101                 if(!paused) {
1102                         // Count down the game loop timer, and change state when it gets to zero or less;
1103
1104                         if((state_timeout -= movementrate*3) < 0) {
1105                                 switch(state) {
1106                                         case DEAD_PAUSE:
1107                                                 // Create a new ship and start all over again
1108                                                 state = GAMEPLAY;
1109                                                 play_tune(1);
1110                                                 initialshield = 0;
1111                                                 xship = 10;
1112                                                 yship = YSIZE/2;
1113                                                 xvel = 3;
1114                                                 yvel = 0;
1115                                                 shieldlevel = 3*W;
1116                                                 for(i = 0; i<MAXROCKS; i++ ) {
1117                                                         if(rock[i].x < STARTSPACE) {
1118                                                                 rock[i].active = 0;
1119                                                         }
1120                                                 }
1121                                         break;
1122                                         case GAME_OVER:
1123                                                 state = HIGH_SCORE_ENTRY;
1124                                                 clearBuffer();
1125                                                 name[0] = 0;
1126                                                 state_timeout = 5.0e6;
1127
1128                                                 if(score >= high[7].score) {
1129                                                         // Read the high score table from the storage file
1130                                                         read_high_score_table();
1131
1132                                                         // Find ranking of this score, store as scorerank
1133                                                         for(i = 0; i<8; i++) {
1134                                                         if(high[i].score <= score) {
1135                                                                 scorerank = i;
1136                                                                 break;
1137                                                         }
1138                                                         }
1139
1140                                                         // Move all lower scores down a notch
1141                                                         for(i = 7; i >= scorerank; i--)
1142                                                         high[i] = high[i-1];
1143
1144                                                         // Insert blank high score
1145                                                         high[scorerank].score = score;
1146                                                         high[scorerank].name = "";
1147                                                         high[scorerank].allocated = 0;
1148                                                 }
1149
1150                                         break;
1151                                         case HIGH_SCORE_DISPLAY:
1152                                                 state = TITLE_PAGE;
1153                                                 state_timeout = 500.0;
1154                                         break;
1155                                         case HIGH_SCORE_ENTRY:
1156                                                 // state = TITLE_PAGE;
1157                                                 // play_tune(1);
1158                                                 // state_timeout = 100.0;
1159                                         break;
1160                                         case TITLE_PAGE:
1161                                                 state = HIGH_SCORE_DISPLAY;
1162                                                 state_timeout = 200.0;
1163                                         break;
1164                                 }
1165                         }
1166
1167                         if(--countdown <= 0 && (rnd()*100.0<(rockrate += 0.025))) {
1168                                 // Create a rock
1169                                 rockptr++;
1170                                 if(rockptr-rock >= MAXROCKS) {
1171                                         rockptr = rock;
1172                                 }
1173                                 if(!rockptr->active) {
1174                                         rockptr->x = (float)XSIZE;
1175                                         rockptr->xvel = -(rockspeed)*(1 + rnd());
1176                                         rockptr->yvel = rnd()-0.5;
1177                                         rockptr->type_number = random() % NROCKS;
1178                                         rockptr->heat = 0;
1179                                         rockptr->image = surf_rock[rockptr->type_number];// [random()%NROCKS];
1180                                         rockptr->active = 1;
1181                                         rockptr->y = rnd()*(YSIZE + rockptr->image->h);
1182                                 }
1183                                 if(movementrate>0.1) {
1184                                         countdown = (int)(ROCKRATE/movementrate);
1185                                 } else {
1186                                         countdown = 0;
1187                                 }
1188                         }
1189
1190                         // FRICTION?
1191                         if(friction) {
1192                                 xvel *= pow((double)0.9,(double)movementrate);
1193                                 yvel *= pow((double)0.9,(double)movementrate);
1194                                 // if(abs(xvel)<0.00001) xvel = 0;
1195                                 // if(abs(yvel)<0.00001) yvel = 0;
1196                         }
1197
1198                         // INERTIA
1199                         xship += xvel*movementrate;
1200                         yship += yvel*movementrate;
1201
1202                         // SCROLLING
1203                         yscroll = yship - (YSIZE / 2);
1204                         yscroll /= -15;
1205                         yscroll = yscroll*movementrate;
1206                         yship += yscroll;
1207                         
1208                         // Move all the rocks
1209                         for(i = 0; i<MAXROCKS; i++) if(rock[i].active) {
1210                                 rock[i].x += rock[i].xvel*movementrate;
1211                                 rock[i].y += rock[i].yvel*movementrate + yscroll;
1212                         if(rock[i].y > YSIZE) {
1213                                 rock[i].y -= YSIZE;
1214                                 rock[i].y -= rock[i].image->w;
1215                         } else if(rock[i].y < -rock[i].image->w) {
1216                                 rock[i].y += YSIZE;
1217                                 rock[i].y += rock[i].image->w;
1218                         }
1219                         if(rock[i].x<-32.0)
1220                                 rock[i].active = 0;
1221                         }
1222
1223
1224                         // BOUNCE X
1225                         if(xship<0 || xship>XSIZE-surf_ship->w) {
1226                                 // BOUNCE from left and right wall
1227                                 xship -= xvel*movementrate;
1228                                 xvel *= -0.99;
1229                         }
1230
1231                         // BOUNCE Y
1232                         if(yship<0 || yship>YSIZE-surf_ship->h) {
1233                                 // BOUNCE from top and bottom wall
1234                                 yship -= yvel;
1235                                 yvel *= -0.99;
1236                         }
1237
1238
1239                         if(draw() && state == GAMEPLAY) {
1240                                 if(oss_sound_flag) {
1241                                         // Play the explosion sound
1242                                         play_sound(0);
1243                                 }
1244                                 makebangdots(xship,yship,xvel,yvel,surf_ship,30);
1245                                 if(--nships <= 0) {
1246                                         gameover = 1;
1247                                         state = GAME_OVER;
1248                                         state_timeout = 200.0;
1249                                         fadetimer = 0.0;
1250                                         faderate = movementrate;
1251                                 }
1252                                 else {
1253                                         state = DEAD_PAUSE;
1254                                         state_timeout = 50.0;
1255
1256                                 }
1257                         }
1258
1259                         SDL_PumpEvents();
1260                         keystate = SDL_GetKeyState(NULL);
1261
1262                         if(state != HIGH_SCORE_ENTRY && (keystate[SDLK_q] || keystate[SDLK_ESCAPE])) {
1263                                 return 0;
1264                         }
1265
1266                         if(keystate[SDLK_SPACE] && (state == HIGH_SCORE_DISPLAY || state == TITLE_PAGE || state == DEMO)) {
1267
1268                                 for(i = 0; i<MAXROCKS; i++ ) {
1269                                         rock[i].active = 0;
1270                                 }
1271
1272                                 rockrate = 54.0;
1273                                 rockspeed = 5.0;
1274
1275                                 nships = 4;
1276                                 score = 0;
1277
1278                                 state = GAMEPLAY;
1279                                 play_tune(1);
1280
1281                                 xvel = -1;
1282                                 gameover = 0;
1283                                 yvel = 0;
1284                                 xship = 0;
1285                                 yship = YSIZE/2;
1286                                 shieldlevel = 3*W;
1287                                 initialshield = 0;
1288
1289                         }
1290
1291                         maneuver = 0;
1292                         laser = 0;
1293                 } else {
1294                         SDL_PumpEvents();
1295                         keystate = SDL_GetKeyState(NULL);
1296                 }
1297
1298                 if(state == GAMEPLAY) {
1299                         if(!gameover) {
1300
1301                                 if(!paused) {
1302                                         if(keystate[SDLK_UP] | keystate[SDLK_c])                { yvel -= 1.5*movementrate; maneuver |= 1<<3;}
1303                                         if(keystate[SDLK_DOWN] | keystate[SDLK_t])              { yvel += 1.5*movementrate; maneuver |= 1<<1;}
1304                                         if(keystate[SDLK_LEFT] | keystate[SDLK_h])              { xvel -= 1.5*movementrate; maneuver |= 1<<2;}
1305                                         if(keystate[SDLK_RIGHT] | keystate[SDLK_n])             { xvel += 1.5*movementrate; maneuver |= 1;}
1306                                         if(keystate[SDLK_3])            { SDL_SaveBMP(surf_screen, "snapshot.bmp"); }
1307                                 }
1308
1309                                 if(keystate[SDLK_p] | keystate[SDLK_s]) {
1310                                         if(!pausedown) {
1311                                                 paused = !paused;
1312                                                 if(paused) {
1313                                                         SDL_Rect src,dest;
1314                                                         src.w = surf_b_variations->w;
1315                                                         src.h = surf_b_variations->h;
1316                                                         dest.w = src.w;
1317                                                         dest.h = src.h;
1318                                                         dest.x = (XSIZE-src.w)/2;
1319                                                         dest.y = (YSIZE-src.h)/2;
1320                                                         SDL_BlitSurface(surf_b_variations,&src,surf_screen,&dest);
1321                                                         // Update the surface
1322                                                         SDL_Flip(surf_screen);
1323                                                 }
1324                                                 pausedown = 1;
1325                                         }
1326                                 } else {
1327                                         pausedown = 0;
1328                                 }
1329
1330                         }
1331                         else {
1332                                 shieldsup = 0;
1333                                 paused = 0;
1334                                 pausedown = 0;
1335                         }
1336                 } else if(state == GAME_OVER) {
1337                         if(keystate[SDLK_SPACE]) {
1338                                 state_timeout = -1;
1339                         }
1340                 }
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("Variations on RockDodger\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
1377         if(init(fullscreen)) {
1378                 printf ("ta: '%s'\n",initerror);
1379                 return 1;
1380         }
1381
1382         while(1) {
1383                 for(i = 0; i<MAXROCKS; i++) {
1384                         rock[i].active = 0;
1385                 }
1386                 rockrate = 54.0;
1387                 rockspeed = 5.0;
1388                 initticks = SDL_GetTicks();
1389                 if(gameloop() == 0) {
1390                         break;
1391                 }
1392                 printf ("score = %d\n",score);
1393                 SDL_Delay(1000);
1394         }
1395
1396         return 0;
1397 }