1 /* moon_lander.c
2 *
3 * copyright 06/26/2001
4 * magigames and dave blood - geekd@yahoo.com
5 *
6 * 07/03/2001 - Mike Heckman
7 *  Added pause capability and compiler options to turn off sound
8 *
9 * 08/14/2001 - Mike Heckman added AI to play demo game, geekd added options
10 * and save/load user options, random backgrounds, and merged MH's AI in
11 *
12 * 08/16/2001 - found most memory leaks and patched them (geekd)
13 *
14 * 08/17/2001 - cleaned up some of the messy code, fixed last of the memory leaks,
15 *  added ryan daniels' ship and thrusters
16 *
17 */
18 
19 
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 
29 #ifndef WIN32_BUILD
30 #include <pwd.h>
31 #endif
32 
33 #include "gamelib.h"
34 #include "DT_drawtext.h"
35 #include "SDL_image.h"
36 
37 #define XSIZE 640
38 #define YSIZE 480
39 #define TERRAIN_YSIZE (YSIZE / 2)
40 #define FPS (1000 / 35)
41 #define DATAPATH "%%PREFIX%%/share/moonlander/"
42 
43 #define FRESHRUN   0
44 #define GAMEOVER   1
45 #define LOST       2
46 #define WON        3
47 #define NEWGAME    4
48 #define AIGAME     5
49 #define BONUS_SHIP 6
50 
51 /************************************************/
52 
53 typedef struct {
54   int r;
55   int g;
56   int b;
57 } RGBcolor;
58 
59 /************************************************/
60 
61 typedef struct {
62   float    difference;
63   float    vdiff;
64   float    max_y;
65   float    target;
66   int      pad;
67   int      distance;
68   int      direction;
69   int      state;
70 } AI;
71 
72 /************************************************/
73 
74 typedef struct {
75   Sprite   sprite;
76   int      landing_x[5];
77   int      landing_y[5];
78   int      landing_w[5];
79   float    landing_speed[5];
80   int      landing_score[5];
81   RGBcolor landing_color[5];
82   int      difficulty;
83   int      fuel;
84   int      num_landings;
85 } Level;
86 
87 /************************************************/
88 
89 typedef struct {
90   int ships_remaining;
91   unsigned int fuel;
92   int score;
93   int difficulty;
94   float gravity;
95   int big_font;
96   int small_font;
97   int demo_mode;
98   int autopilot;
99   int state;
100   int ActualTime, LastTime;
101   int landing_pad;
102   int back_no;
103   SDL_Surface *screen;
104   Sprite explosion[25];
105   Sprite ship;
106   Sprite background;
107   Sprite thrust;
108   Sprite thrustb;
109   Sprite thrust_left;
110   Sprite thrust_right;
111   Sprite miniship;
112   Sprite logo;
113   Sprite gameover_screen;
114   Sprite magigames;
115   Level current_level;
116   int opt_prog_grav;
117   int opt_lp_bonus;
118   int opt_lp_warn;
119   int opt_num_lives;
120   int opt_fancy_terrain;
121   AI ai;
122 #ifndef NOSOUND
123   Mix_Chunk *engine;
124   Mix_Chunk *new_life;
125   Mix_Chunk *explosion_a;
126   Mix_Chunk *on;
127   Mix_Chunk *off;
128   Mix_Chunk *ready;
129   Mix_Chunk *go;
130   Mix_Chunk *eagle_landed;
131 #endif
132 } Game;
133 
134 
135 /************************************************/
136 
delay(int t)137 void delay(int t){
138   SDL_Event event;
139   Uint8 *key_table;
140   int i;
141 
142   for (i = 0;i < t; i++){
143 
144     SDL_PollEvent(&event);
145 
146     if (event.type == SDL_QUIT){
147       exit(0);
148     }
149 
150     key_table = SDL_GetKeyState(NULL);
151 
152     if (key_table[SDLK_q]){
153       exit(0);
154     }
155 
156     SDL_Delay(20);
157   }
158 }
159 
160 /************************************************/
161 
frame_rate_limiter(Game * game)162 void frame_rate_limiter(Game *game){
163 
164   /* timer - so that things run at an even speed regardless of cpu speed */
165 
166   game->ActualTime = SDL_GetTicks();
167   if (game->ActualTime < game->LastTime + FPS){
168     SDL_Delay(game->LastTime + FPS - game->ActualTime);
169   }
170   game->LastTime = game->ActualTime;
171 }
172 
173 /************************************************/
174 
get_new_background(Game * game)175 void get_new_background(Game *game) {
176 
177   char filename[1024];
178   DIR *dir;
179   char *bg[100];
180   struct dirent *d;
181   int count = 0;
182   int i;
183 
184   /* read images/backgrounds dir and choose a random image from there.
185    *  put it's filename in image_file
186    */
187 
188 
189 
190     snprintf(filename, sizeof filename, "%simages/backgrounds",  DATAPATH);
191 
192     if ( !(dir = opendir(filename)) ){
193       /* error */
194       printf("cannot open dir %s\n", filename);
195       exit(0);
196     }
197 
198     while ( (d = readdir(dir)) != NULL){
199     	if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
200 	    continue;
201 	bg[count++] = strdup(d->d_name);
202 	if (count >= 100)
203 	    break;
204     }
205 
206     closedir(dir);
207 
208 
209   if (!count){
210     printf("I got no images for backgrounds - ERROR\n");
211     exit(0);
212   }
213 
214 
215 
216 
217   game->back_no++;
218 
219   if (game->back_no < 0){
220     game->back_no = 0;
221   }
222 
223   if (game->back_no >= count){
224     game->back_no = 0;
225   }
226 
227 
228   if (game->background.image != NULL){
229     //printf("about to free background\n");
230     SDL_FreeSurface(game->background.image);
231   }
232   else{
233     //printf("background was NULL\n");
234   }
235 
236   //printf("about to get new background: %d\n", game->back_no );
237 
238   snprintf(filename, sizeof(filename), "%simages/backgrounds/%s", DATAPATH, bg[game->back_no]);
239   for (i = 0; i < count; i++)
240   	free(bg[i]);
241 
242   // printf("got %s\n", filename);
243 
244   new_sprite(&(game->background), filename, 0, 0, 0, 0);
245   //  printf("got new background\n");
246 
247 
248 }
249 
250 /************************************************/
251 
save_game(Game * game)252 void save_game(Game *game){
253   char filename[200];
254   FILE *file;
255 
256 #ifndef WIN32_BUILD
257   struct passwd *pwp;
258 
259 
260   /* get user home dir */
261   if ( !(pwp = getpwuid(getuid()))){
262     // error
263     printf("attempt to get current user failed\n");
264     exit(0);
265   }
266 
267   sprintf(filename, "%s/.moon_lander", pwp->pw_dir);
268 #endif
269 
270 #ifdef WIN32_BUILD
271   sprintf(filename, "moon_lander.conf");
272 #endif
273 
274   printf("saving game options in %s\n", filename);
275 
276   if ( (file = fopen(filename, "w")) != NULL) {
277 
278     fprintf(file,"%d %d %d %d %d",  game->opt_num_lives, game->opt_lp_bonus,game->opt_lp_warn,
279 	    game->opt_prog_grav,game->opt_fancy_terrain);
280 
281   }
282   else{
283     printf("cannot open file for saving: %s\n", filename);
284   }
285 
286   fclose(file);
287 }
288 
289 /************************************************/
290 
load_game(Game * game)291 void load_game(Game *game){
292 
293   char filename[200];
294   FILE *file;
295 
296 #ifndef WIN32_BUILD
297   struct passwd *pwp;
298 
299   /* get user home dir */
300   if ( !(pwp = getpwuid(getuid()))){
301     // error
302     printf("attempt to get current user failed\n");
303     exit(0);
304   }
305 
306   sprintf(filename, "%s/.moon_lander", pwp->pw_dir);
307 #endif
308 
309 #ifdef WIN32_BUILD
310   sprintf(filename, "moon_lander.conf");
311 #endif
312 
313   printf("reading game options in %s\n", filename);
314 
315   if ( (file = fopen(filename, "r")) != NULL) {
316 
317     fscanf(file,"%d %d %d %d %d",  &game->opt_num_lives, &game->opt_lp_bonus, &game->opt_lp_warn,
318 	    &game->opt_prog_grav, &game->opt_fancy_terrain);
319 
320   }
321   else{
322     printf("cannot open file for reading: %s - loading defaults\n", filename);
323 
324     /* defaults */
325     game->opt_num_lives = 3;
326     game->opt_lp_bonus = 1;
327     game->opt_lp_warn = 1;
328     game->opt_prog_grav = 1;
329     game->opt_fancy_terrain = 1;
330 
331     return;
332   }
333 
334   fclose(file);
335 }
336 
337 
338 /************************************************/
339 
options(Game * game)340 void options (Game *game) {
341   int done = 0;
342   int *selected;
343   int position = 0;
344   char options[5][100];
345   char display_string[150];
346   char selected_text[2];
347   int count;
348   int value[5];
349   Uint8 *key_table;
350   SDL_Event event;
351 
352   sprintf(options[0],"%s", "Fancy Terrain");
353   sprintf(options[1],"%s", "Progressive Gravity");
354   sprintf(options[2],"%s", "Landing Pad Speed Warning");
355   sprintf(options[3],"%s", "Variable Speed Landing Pads");
356   sprintf(options[4],"%s", "Number Of Ships");
357 
358 
359   /* clear event buffer */
360   while (SDL_PollEvent(&event)){};
361 
362   while (done == 0) {
363 
364     SDL_WaitEvent(&event);
365 
366     if (event.type == SDL_QUIT) {
367       exit(0);
368     }
369 
370     key_table = SDL_GetKeyState(NULL);
371 
372     if (key_table[SDLK_q]){
373       exit(0);
374     }
375 
376     if (key_table[SDLK_ESCAPE]){
377       done = 1;
378     }
379 
380     if (key_table[SDLK_UP]){
381       position--;
382       if (position < 0){
383 	position = 4;
384       }
385     }
386 
387     if (key_table[SDLK_DOWN]){
388       position++;
389       if (position >4){
390 	position = 0;
391       }
392     }
393 
394     if (key_table[SDLK_RETURN]){
395       (*selected)++;
396 
397       if (position == 4){
398 	if (*selected > 5){
399 	  *selected = 1;
400 	}
401       }
402       else{
403 	if (*selected > 1){
404 	  *selected = 0;
405 	}
406       }
407 
408     }
409 
410     /* point selected at proper value */
411 
412     if (position == 0){
413       selected = &(game->opt_fancy_terrain);
414     }
415     else if (position == 1){
416       selected = &(game->opt_prog_grav);
417     }
418     else if (position == 2){
419       selected = &(game->opt_lp_warn);
420     }
421     else if (position == 3){
422       selected = &(game->opt_lp_bonus);
423     }
424     else if (position == 4){
425       selected = &(game->opt_num_lives);
426     }
427 
428     value[0] = game->opt_fancy_terrain;
429     value[1] = game->opt_prog_grav;
430     value[2] = game->opt_lp_warn;
431     value[3] = game->opt_lp_bonus;
432     value[4] = game->opt_num_lives;
433 
434 
435     /* draw the options */
436     draw_sprite(game->screen, game->background);
437     DT_DrawText("OPTIONS", game->screen, game->big_font, 260, 50);
438     DT_DrawText("Arrow Keys Select", game->screen, game->small_font, 260, 75);
439     DT_DrawText("ENTER changes value", game->screen, game->small_font, 260, 90);
440 
441     for (count = 0; count < 5; count ++) {
442 
443       if (position == count) {
444 	sprintf(selected_text,"%s","**");
445       }
446       else {
447 	sprintf(selected_text,"%s","  ");
448       }
449 
450       sprintf(display_string, "%s %s - %d", selected_text, options[count], value[count] );
451       DT_DrawText(display_string, game->screen, game->big_font, 50, 150 + (count * 50) );
452 
453     }
454 
455     delay(3);
456     SDL_Flip(game->screen);
457 
458   } /* end while */
459 
460   save_game(game);
461 
462   /* clear event buffer */
463   delay(5);
464   while (SDL_PollEvent(&event)){};
465 }
466 
467 
468 /************************************************/
469 
470 
remaining_ships(Game * game)471 void remaining_ships(Game *game) {
472   int count;
473 
474   // Draw in the remaining ships
475   for( count = 0; count < game->ships_remaining; count++ ) {
476     game->miniship.x = (22 * count);
477     game->miniship.y = 15;
478     draw_sprite(game->screen, game->miniship );
479   }
480 
481 }
482 
483 
484 /************************************************/
485 
486 
DrawPixel(SDL_Surface * screen,Uint8 R,Uint8 G,Uint8 B,int x,int y)487 void DrawPixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B, int x, int y)
488 {
489 
490      Uint32 color = SDL_MapRGB(screen->format, R, G, B);
491      Uint16 *bufp;
492 
493      bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
494     *bufp = color;
495 
496 
497 }
498 
499 /************************************************/
500 
draw_line(SDL_Surface * screen,Uint8 R,Uint8 G,Uint8 B,int x,int y)501 void draw_line(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B, int x, int y) {
502 
503   for(; y < TERRAIN_YSIZE; y++){
504     DrawPixel(screen, R, G, B, x, y);
505   }
506 
507 }
508 
509 /************************************************/
510 
511 /* This draws a line that is composed of n repeating gradients
512     implemented by BMD  */
513 
draw_terrain_line(SDL_Surface * screen,int x,int y)514 void draw_terrain_line( SDL_Surface *screen, int x, int y )
515 {
516     int gradient_iterations = 3;
517     int dark_color = 80;
518     int gradient_color_variance = 40;
519 
520     int gradient_height = (TERRAIN_YSIZE-y)/gradient_iterations;
521 
522     for(; y < TERRAIN_YSIZE; y++)
523     {
524         int height = TERRAIN_YSIZE-y;
525         double gradient_ratio = (double)(height%gradient_height)/gradient_height;
526         int color = gradient_ratio * gradient_color_variance + dark_color;
527         DrawPixel(screen, color, color, color, x, y);
528     }
529 }
530 
531 /************************************************/
532 
random_level(Game * game)533 void random_level(Game *game) {
534   SDL_Surface *tmp;
535   int x = 0;
536   int y = 0;
537   int yd = 0;
538   int miny = 0;
539   int maxy = 0;
540   int yfluct = 0;
541   int size = 0;
542   int max = 0;
543   float speed;
544   RGBcolor rgb;
545   float distance;
546   int xdiff;
547   int ydiff;
548   char filename[100];
549 
550   //printf("random level\n");
551 
552   game->current_level.num_landings = 0;
553   game->current_level.difficulty = game->difficulty;
554 
555   // printf("getting new background\n");
556 
557   get_new_background(game);
558 
559 
560   while (game->current_level.num_landings == 0){
561 
562     // printf("starting while loop\n");
563 
564     if (game->current_level.sprite.image != NULL){
565       SDL_FreeSurface(game->current_level.sprite.image);
566     }
567 
568     sprintf(filename, "%simages/blank_terrain.gif", DATAPATH);
569     tmp = IMG_Load(filename);
570     if (tmp == NULL ) {
571       fprintf(stderr, "Couldn't load %s: %s\n", filename, SDL_GetError());
572       exit(1);
573     }
574 
575     game->current_level.sprite.image = SDL_DisplayFormat(tmp);
576 
577     SDL_FreeSurface(tmp);
578 
579     SDL_LockSurface(game->current_level.sprite.image);
580 
581 #ifndef WIN32_BUILD
582     srandom(time(NULL));
583 
584     while ( (y > 230) || (y < 10) ){
585       y = random()%TERRAIN_YSIZE;
586     }
587 
588     miny = ( (random()%(TERRAIN_YSIZE/2)) + 10);
589     maxy = ( (random()%(TERRAIN_YSIZE/2) + TERRAIN_YSIZE/2) -10 );
590 #endif
591 
592 #ifdef WIN32_BUILD
593     srand(time(NULL));
594 
595     while ( (y > 230) || (y < 10) ){
596       y = rand()%TERRAIN_YSIZE;
597     }
598 
599     miny = ( (rand()%(TERRAIN_YSIZE/2)) + 10);
600     maxy = ( (rand()%(TERRAIN_YSIZE/2) + TERRAIN_YSIZE/2) -10 );
601 #endif
602 
603     if (y > (TERRAIN_YSIZE/2)){
604       yd = -1;
605     }
606     else{
607       yd = 1;
608     }
609 
610 
611     /* start to draw */
612 
613     for (x = 0; x < XSIZE; x++){
614 
615       if ( (x % 3) == 0){
616 #ifndef WIN32_BUILD
617 	yfluct = ( (random()%10) - 5);
618 #endif
619 #ifdef WIN32_BUILD
620 	yfluct = ( (rand()%10) - 5);
621 #endif
622       }
623 
624       if ( ( (y < maxy) && (y > miny)) || ( (y > maxy) && (yfluct < 1) )
625 	   || ( (y < maxy) && (yfluct > -1) ) ){
626 
627 	y = y + yfluct;
628 
629       }
630 
631       /* draw landscape */
632 
633       if (game->opt_fancy_terrain){
634 	draw_terrain_line(game->current_level.sprite.image, x, y);
635       }
636       else {
637 	draw_line(game->current_level.sprite.image, 80, 80, 80, x, y);
638       }
639 
640       /* check for change direction */
641 
642       if (yd == 1){
643 
644 	if (y > maxy){
645 
646 	  if ( (x < (XSIZE - 60) ) && (game->current_level.num_landings < 4) ){
647 
648 	    /* landing pad */
649 
650 	    size = (40 + (15 - ( game->difficulty / 2 ) ) );
651 	    max = x + size;
652 
653 	    game->current_level.landing_x[game->current_level.num_landings] = x;
654 	    game->current_level.landing_y[game->current_level.num_landings] = (y + TERRAIN_YSIZE);;
655 	    game->current_level.landing_w[game->current_level.num_landings] = size;
656 
657             /* get distance from center-top */
658             xdiff = ((XSIZE / 2) -  x );
659             ydiff = ( y );
660 
661             if (xdiff == 0){
662               distance = ydiff;
663             }
664             else if (ydiff == 0){
665               distance = xdiff;
666             }
667             else {
668               distance = sqrt( ( xdiff * xdiff  ) + (ydiff * ydiff ) );
669 	    }
670 
671 	    game->current_level.landing_speed[game->current_level.num_landings] = 1.00;
672 	    game->current_level.landing_score[game->current_level.num_landings] =
673 	      ( ( (16 - (size - 45) ) * 100) +
674 		( (distance / 4) * ( (game->difficulty / 2) + 1) ) );
675 
676 	    // Default landing pad color is blue
677 	    rgb.r = 0;
678 	    rgb.g = 0;
679 	    rgb.b = 255;
680 
681 	    /* ----------- bonus colored landing pads if on ------- */
682 	    if (game->opt_lp_bonus){
683 	      if( game->current_level.num_landings ) {
684 #ifndef WIN32_BUILD
685 		speed = ( random() % 3 );
686 #endif
687 
688 #ifdef WIN32_BUILD
689 		speed = ( rand() % 3 );
690 #endif
691 
692 		// Magenta is for landings at .90
693 		if( speed > 0  ) {
694 		  rgb.r = 255;
695 		  rgb.g = 0;
696 		  rgb.b = 255;
697 		}
698 		// Green for landings at .80
699 		if( speed > 1 ) {
700 		  rgb.r = 0;
701 		  rgb.g = 255;
702 		  rgb.b = 0;
703 		}
704 
705 		// Set the landing speed and score
706 		game->current_level.landing_speed[game->current_level.num_landings] -= (speed * .1);
707 		game->current_level.landing_score[game->current_level.num_landings] += (speed * 100);
708 	      }
709 	    }
710 
711 
712 	    game->current_level.landing_color[game->current_level.num_landings] = rgb;
713 
714 	    // Write the landing pads onto the terrain
715 	    for (; x < max; x++){
716 	      DrawPixel(game->current_level.sprite.image, rgb.r, rgb.g, rgb.b, x, y);
717 	      DrawPixel(game->current_level.sprite.image, rgb.r, rgb.g, rgb.b, x, y+1);
718 	      DrawPixel(game->current_level.sprite.image, rgb.r, rgb.g, rgb.b, x, y+2);
719 
720 	      if (game->opt_fancy_terrain){
721 		draw_terrain_line(game->current_level.sprite.image, x, y + 3);
722 	      }
723 	      else {
724 		draw_line(game->current_level.sprite.image, 80, 80, 80, x, y + 3);
725 	      }
726 	    }
727 
728 	    x--;
729 	    game->current_level.num_landings++;
730 	  }
731 
732 	  yd = -1;
733 #ifndef WIN32_BUILD
734 	  miny = ( (random()%(TERRAIN_YSIZE/2)) + 10);
735 	  maxy = ( (random()%(TERRAIN_YSIZE/2) + TERRAIN_YSIZE/2) - 25 );
736 #endif
737 #ifdef WIN32_BUILD
738 	  miny = ( (rand()%(TERRAIN_YSIZE/2)) + 10);
739 	  maxy = ( (rand()%(TERRAIN_YSIZE/2) + TERRAIN_YSIZE/2) - 25 );
740 #endif
741 
742 	}
743 
744       }
745 
746       if (yd == -1){
747 	if (y < miny){
748 	  yd = 1;
749 #ifndef WIN32_BUILD
750 	  miny = ( (random()%(TERRAIN_YSIZE/2)) + 10);
751 	  maxy = ( (random()%(TERRAIN_YSIZE/2) + TERRAIN_YSIZE/2) - 10 );
752 #endif
753 #ifdef WIN32_BUILD
754 	  miny = ( (rand()%(TERRAIN_YSIZE/2)) + 10);
755 	  maxy = ( (rand()%(TERRAIN_YSIZE/2) + TERRAIN_YSIZE/2) - 10 );
756 #endif
757 	}
758       }
759 
760       y = y + yd;
761 
762     }
763 
764     SDL_UnlockSurface(game->current_level.sprite.image);
765 
766     new_sprite_surface(&(game->current_level.sprite), game->current_level.sprite.image, 0, TERRAIN_YSIZE, 1);
767 
768     game->current_level.fuel = (700 - (game->difficulty * 25));
769 
770     if (game->current_level.fuel < 300){
771       game->current_level.fuel = 300;
772     }
773 
774   }
775 
776 }
777 
778 /************************************************/
779 
draw_score(Game * game,int landing_score)780 void draw_score(Game *game, int landing_score){
781   char display_string[100];
782   int count;
783 
784   sprintf(display_string, "Fuel %d", game->fuel);
785 
786   if (game->small_font > -1){
787     DT_DrawText(display_string, game->screen, game->small_font, 1, 1 );
788   }
789 
790   sprintf(display_string, "X Velocity %.2f", game->ship.x_vel);
791 
792   if (game->small_font > -1){
793     DT_DrawText(display_string, game->screen, game->small_font, 100, 1);
794   }
795 
796   sprintf(display_string, "Y Velocity %.2f", game->ship.y_vel);
797 
798   if (game->small_font > -1){
799     DT_DrawText(display_string, game->screen, game->small_font, 250, 1);
800   }
801 
802   sprintf(display_string, "Score: %d", game->score);
803 
804   if (game->small_font > -1){
805     DT_DrawText(display_string, game->screen, game->small_font, 500, 1);
806   }
807 
808   if (landing_score){
809 
810     for (count = 0; count < game->current_level.num_landings; count++){
811       sprintf(display_string, "%d", game->current_level.landing_score[count] );
812 
813       if (game->small_font > -1){
814 	DT_DrawText(display_string, game->screen, game->small_font,
815 		    ( game->current_level.landing_x[count] + 5 ),
816 		    ( game->current_level.landing_y[count] + 5 ));
817       }
818 
819     }
820   }
821 
822 
823 }
824 
825 
826 /************************************************/
827 
game_over(Game * game,int first_time)828 void game_over(Game *game, int first_time){
829 
830   SDL_Event event;
831   int x;
832   int y = 375;
833   int done = 0;
834   int ticks = 0;
835   Uint8 *key_table;
836   int l_start;
837 
838 
839   if( game->demo_mode ) {
840     first_time = 1;
841     game->score = 0;
842     game->difficulty = 0;
843     game->ships_remaining = game->opt_num_lives;
844     game->gravity = 0.05;
845   }
846 
847   if (first_time == 0){
848   /* if they just lost, show them thier score and stuff and then pause for a sec */
849     draw_sprite(game->screen, game->gameover_screen);
850     draw_sprite(game->screen, game->logo);
851     DT_DrawText("Game Over", game->screen, game->big_font, 252, 148 );
852     draw_score(game, 0);
853     draw_sprite(game->screen, game->magigames);
854 
855     SDL_Flip(game->screen);
856     delay(75);
857   }
858 
859   /* start between game animation */
860   l_start=60;
861 
862 
863 
864   while (!done) {
865     ticks++;
866 
867     draw_sprite(game->screen, game->gameover_screen);
868     draw_sprite(game->screen, game->logo);
869     draw_sprite(game->screen, game->magigames);
870 
871     /* show the game name, etc */
872 
873     /* if they just lost, show them thier score and stuff */
874 
875     if (first_time == 0){
876       DT_DrawText("Game Over", game->screen, game->big_font, 252, 148 );
877     }
878 
879     draw_score(game, 0);
880     DT_DrawText("Arrow keys control the ship", game->screen, game->big_font, 100, 100 );
881     DT_DrawText("Q quit   P pause   ESC options", game->screen, game->big_font, 75, 125 );
882     DT_DrawText("Press ENTER to play", game->screen, game->big_font, 175, 170 );
883 
884     DT_DrawText("Score for each round = landing pad score + remaining fuel.", game->screen, game->small_font, 150, 280 );
885     DT_DrawText("Safe Landing requires X velocity < 0.5 and Y velocity < indicated by landing pad color.", game->screen, game->small_font, 55, 300 );
886     DT_DrawText("Free ship every 10,000 points", game->screen, game->small_font, 225, 340 );
887 
888     /* do the pad display thing */
889     SDL_LockSurface(game->screen);
890     for (x=0; x < XSIZE; x++){
891 
892       if ( (x > (XSIZE / 8 - 25) ) && ( x < (XSIZE / 8 + 30)) && (ticks > l_start * 1) && (ticks < (l_start * 5)) ){
893 	DrawPixel(game->screen, 0, 0, 255, x, y);
894 	DrawPixel(game->screen, 0, 0, 255, x, y+1);
895 	DrawPixel(game->screen, 0, 0, 255, x, y+2);
896       }
897 
898       if ( (x > (XSIZE / 2.67 - 25) ) && ( x < (XSIZE / 2.67 + 30)) && (game->opt_lp_warn)
899 	   && (ticks > (l_start * 2)) && (ticks <  (l_start * 6) ) ){
900 	DrawPixel(game->screen, 255, 0, 0, x, y);
901 	DrawPixel(game->screen, 255, 0, 0, x, y+1);
902 	DrawPixel(game->screen, 255, 0, 0, x, y+2);
903       }
904 
905       if ( (x > (XSIZE / 1.6 - 25) ) && ( x < (XSIZE / 1.6 + 30)) && (game->opt_lp_bonus)
906 	   && (ticks > (l_start * 3)) && (ticks < (l_start * 7)) ){
907 	DrawPixel(game->screen, 0, 255, 0, x, y);
908 	DrawPixel(game->screen, 0, 255, 0, x, y+1);
909 	DrawPixel(game->screen, 0, 255, 0, x, y+2);
910       }
911 
912       if ( (x > (XSIZE / 1.14 - 25) ) && ( x < (XSIZE / 1.14 + 30)) && (game->opt_lp_bonus)
913 	   && (ticks > (l_start * 4)) && (ticks <  (l_start * 8)) ){
914 	DrawPixel(game->screen, 255, 0, 255, x, y);
915 	DrawPixel(game->screen, 255, 0, 255, x, y+1);
916 	DrawPixel(game->screen, 255, 0, 255, x, y+2);
917       }
918     }
919 
920 
921     SDL_UnlockSurface(game->screen);
922 
923     if ( (ticks > (l_start * 1)) && (ticks <  (l_start * 5) ) ){
924       DT_DrawText("Landing Vel. = 1.0", game->screen, game->small_font, (XSIZE / 8 - 50), y + 10 );
925     }
926 
927     if ( (game->opt_lp_warn) && (ticks > (l_start * 2)) && (ticks <  (l_start * 6) ) ){
928       DT_DrawText("Red  = Too Fast!", game->screen, game->small_font, (XSIZE / 2.67 - 50), y + 10 );
929     }
930 
931     if ( (game->opt_lp_bonus) && (ticks > (l_start * 3)) && (ticks <  (l_start * 7)  ) ){
932       DT_DrawText("Landing Vel. = 0.8", game->screen, game->small_font, (XSIZE / 1.6 - 50), y + 10 );
933     }
934 
935     if ( (game->opt_lp_bonus) && (ticks > (l_start * 4)) && (ticks <  (l_start * 8)  ) ){
936       DT_DrawText("Landing Vel. = 0.9", game->screen, game->small_font, (XSIZE / 1.14 - 50), y + 10 );
937     }
938 
939     if( ( game->opt_lp_bonus ) && ( ticks > ( l_start * 9)) ) {
940       game->score = 0;
941       game->difficulty = 0;
942       game->ships_remaining = 0;
943       game->gravity = 0.05;
944       game->state = AIGAME;
945       done = 1;
946     }
947 
948 #ifndef NOSOUND
949     /* play a sound when the pads appear and dissapear */
950 
951     if ( (ticks == (l_start * 1) ) || ((ticks == (l_start * 2)) && (game->opt_lp_warn))
952 	 || ((ticks == (l_start * 3)) && (game->opt_lp_bonus)) || ((ticks == (l_start * 4)) && (game->opt_lp_bonus)) ){
953       play_audio(game->on, 0);
954     }
955 
956     if ( (ticks == (l_start * 5)) || ((ticks == (l_start * 6)) && (game->opt_lp_warn))
957 	 || ((ticks == (l_start * 7)) && (game->opt_lp_bonus)) || ((ticks == (l_start * 8)) && (game->opt_lp_bonus)) ){
958       play_audio(game->off, 0);
959     }
960 #endif
961 
962     if (ticks > (l_start * 9) ) {
963       ticks = 0;
964     }
965     SDL_Flip(game->screen);
966 
967 
968     /* press ENTER to play */
969     SDL_PollEvent(&event);
970 
971     if (event.type == SDL_QUIT){
972       exit(0);
973     }
974 
975     key_table = SDL_GetKeyState(NULL);
976 
977     if (key_table[SDLK_q]){
978       exit(0);
979     }
980 
981 
982     if (key_table[SDLK_RETURN]){
983       done = 1;
984       game->demo_mode = 0;
985       game->score = 0;
986       game->difficulty = 0;
987       game->ships_remaining = game->opt_num_lives;
988       game->gravity = 0.05;
989       game->state = NEWGAME;
990     }
991 
992     if (key_table[SDLK_ESCAPE]){
993       options(game);
994     }
995 
996     frame_rate_limiter(game);
997 
998   } /* end while */
999 
1000 
1001   /* reset all the stuff for a new game */
1002 
1003   game->score = 0;
1004   game->difficulty = 0;
1005   game->ships_remaining = (game->opt_num_lives - 1);
1006   game->gravity = 0.05;
1007 
1008 
1009 
1010 }
1011 
1012 
1013 /************************************************/
1014 
new_round(Game * game,int died_won)1015 void new_round(Game *game, int died_won) {
1016 
1017   SDL_Event event;
1018   char display_string[100];
1019 
1020 
1021   //printf("new round\n");
1022 
1023   /* clear event buffer */
1024 
1025   while (SDL_PollEvent(&event)){};
1026 
1027   /* reset ship */
1028   game->ship.x = XSIZE / 2;
1029   game->ship.y = 1;
1030   game->ship.y_vel=0;
1031   game->ship.x_vel=0;
1032 
1033 
1034   if (died_won == 0){  /* died */
1035     game->ships_remaining--;
1036     game->fuel = game->current_level.fuel;
1037     //level = current_level;
1038   }
1039 
1040   else if (died_won == 1) {  /* won */
1041     game->difficulty++;
1042 
1043     /* get new level */
1044 
1045 
1046     random_level(game);
1047 
1048     game->fuel = game->current_level.fuel;
1049 
1050     /* prograssive gravity if on */
1051     if (game->opt_prog_grav){
1052       game->gravity = 0.05 + (game->difficulty * 0.001 );
1053     }
1054 
1055 
1056   }
1057   else if (died_won == 3) { /* starting new game */
1058 
1059     random_level(game) ;
1060     game->fuel = game->current_level.fuel;
1061   }
1062 
1063 
1064 
1065   /* draw start round screen */
1066 
1067   draw_sprite(game->screen, game->background);
1068   remaining_ships(game );
1069   draw_sprite(game->screen, game->ship);
1070   draw_sprite(game->screen, game->current_level.sprite);
1071 
1072   /* message 1  */
1073 
1074   draw_score(game, 1);
1075 
1076   if (game->difficulty == 4) {
1077     DT_DrawText("Not Bad", game->screen, game->big_font, 250, 250 );
1078   }
1079 
1080   else if (game->difficulty == 9){
1081     DT_DrawText("You think you're hot shit, huh?", game->screen, game->big_font, 125, 250 );
1082   }
1083 
1084   else if (game->difficulty == 14){
1085     DT_DrawText("Starfleet called, they want to", game->screen, game->big_font, 100, 235 );
1086     DT_DrawText("offer you a job", game->screen, game->big_font, 174, 260 );
1087   }
1088 
1089   else if (game->difficulty == 19){
1090     DT_DrawText("The force is strong in you", game->screen, game->big_font, 125, 250 );
1091   }
1092 
1093 
1094   sprintf(display_string, "Level: %d", (game->difficulty) + 1);
1095   DT_DrawText(display_string, game->screen, game->big_font, 250, 150 );
1096 
1097 
1098   /* flip screen so they show up */
1099 #ifndef NOSOUND
1100   play_audio(game->ready, 1);
1101 #endif
1102   SDL_Flip(game->screen);
1103 
1104   if( game->demo_mode == 1 ) {
1105     return;
1106   }
1107 
1108   delay(75);
1109 
1110   /* message 2  */
1111 
1112   draw_sprite(game->screen, game->background);
1113   remaining_ships(game );
1114   draw_sprite(game->screen, game->ship);
1115   draw_sprite(game->screen, game->current_level.sprite);
1116 
1117   draw_score(game,  1);
1118 
1119   DT_DrawText("Ready...", game->screen, game->big_font, 250, 150 );
1120 
1121   /* flip screen so they show up */
1122 #ifndef NOSOUND
1123   play_audio(game->ready, 1);
1124 #endif
1125   SDL_Flip(game->screen);
1126 
1127   delay(70);
1128 
1129   draw_sprite(game->screen, game->background);
1130   remaining_ships(game );
1131   draw_sprite(game->screen, game->ship);
1132   draw_sprite(game->screen, game->current_level.sprite);
1133   // Draw in the remaining ships
1134 
1135   /* display fuel  */
1136 
1137   draw_score(game,  1);
1138 
1139   DT_DrawText("GO!", game->screen, game->big_font, 290, 150 );
1140 
1141       /* flip screen so they show up */
1142 #ifndef NOSOUND
1143   play_audio(game->go, 0);
1144 #endif
1145   SDL_Flip(game->screen);
1146 
1147   delay(25);
1148 
1149 
1150   /* clear event buffer */
1151   while (SDL_PollEvent(&event)){}
1152 
1153 }
1154 
1155 
1156 /************************************************/
1157 
explode(Sprite exploder,Sprite terrain,Game * game)1158 void explode (Sprite exploder,
1159 	      Sprite terrain,
1160 	      Game *game
1161 	      ) {
1162 
1163   int count;
1164 
1165 #ifndef NOSOUND
1166   play_audio(game->explosion_a, 0);
1167 #endif
1168 
1169   for (count = 1; count < 27; count++){
1170     game->explosion[count-1].x = ( (exploder.x + (exploder.w / 2)) - (game->explosion[count-1].w / 2) );
1171     game->explosion[count-1].y = ( (exploder.y + (exploder.h / 2)) - (game->explosion[count-1].h / 2) );
1172 
1173     draw_sprite(game->screen, game->background);
1174     remaining_ships(game );
1175     draw_sprite(game->screen, terrain);
1176 
1177     if (count < 26) {
1178       draw_sprite(game->screen, game->explosion[count-1]);
1179     }
1180 
1181     /* display fuel  */
1182 
1183     draw_score(game, 1);
1184 
1185 
1186     /* Update the screen */
1187 
1188     SDL_Flip(game->screen);
1189 
1190     /* timer - so that things run at an even speed regardless of cpu speed */
1191 
1192     frame_rate_limiter(game);
1193 
1194 
1195   }
1196 
1197   delay(30);
1198 
1199 }
1200 
1201 /************************************************/
1202 
win(Game * game,int bonus)1203 void win (Game *game, int bonus) {
1204 
1205   game->score += game->current_level.landing_score[game->landing_pad];
1206 
1207 #ifndef NOSOUND
1208   Mix_HaltChannel(1);
1209   /* congrats sound here */
1210   play_audio(game->eagle_landed, 0);
1211 #endif
1212 
1213   draw_sprite(game->screen, game->background);
1214   remaining_ships(game );
1215   draw_sprite(game->screen, game->current_level.sprite);
1216   draw_score(game, 1);
1217   draw_sprite(game->screen, game->ship);
1218 
1219   if (game->big_font > -1){
1220     DT_DrawText("Excellent", game->screen, game->big_font, (XSIZE / 2) - 66, (YSIZE / 3) - 9 );
1221   }
1222 
1223   /* Update the screen */
1224   SDL_Flip(game->screen);
1225   delay(80);
1226 
1227   if (bonus){
1228     game->ships_remaining++;
1229 
1230 #ifndef NOSOUND
1231     play_audio(game->new_life, 1);
1232 #endif
1233 
1234     draw_sprite(game->screen, game->background);
1235     remaining_ships(game );
1236     draw_sprite(game->screen, game->current_level.sprite);
1237     draw_score(game, 1);
1238     draw_sprite(game->screen, game->ship);
1239 
1240     if (game->big_font > -1){
1241       DT_DrawText("Excellent", game->screen, game->big_font, (XSIZE / 2) - 66, (YSIZE / 3) - 9 );
1242       DT_DrawText("Bonus Ship", game->screen, game->big_font, (XSIZE / 2) - 70, (YSIZE / 3) + 40 );
1243     }
1244 
1245     /* Update the screen */
1246 
1247     SDL_Flip(game->screen);
1248     delay(80);
1249   }
1250 
1251  }
1252 
1253 /************************************************/
1254 
gameai(int * left,int * right,int * down,Game * game)1255 void gameai( int *left,
1256 	     int *right,
1257 	     int *down,
1258 	     Game *game)
1259 {
1260   int count;
1261 
1262   /* -------------------------------------------------------------
1263      Game AI -- written by Michael Heckman 07/17/2001
1264 
1265      Ok, so we're going to divide the AI into several states:
1266 
1267      0 => Figure out the direction
1268      1 => Burn until we're half way there
1269      2 => Burn in the opposite direction
1270      3 => once we've reached the pad, cancel out any remaining
1271      velocity.
1272      4 => Freefall with minor course changes
1273 
1274      ------------------------------------------------------------- */
1275   *left = 0;
1276   *right = 0;
1277 
1278   // AI State
1279   /* --- state 0, locate the pad and init variables --- */
1280   if( game->ai.state == 0 ) {
1281     game->ai.vdiff = 0;
1282 
1283     // Find which pad we're going to take.
1284     game->ai.pad = 0;
1285     game->ai.distance = 9999;
1286     for( count = 0; count < game->current_level.num_landings; count++ ) {
1287       if( abs( 320 - game->current_level.landing_x[count] ) < game->ai.distance ) {
1288 	game->ai.distance = abs( 320 - game->current_level.landing_x[count] );
1289 	game->ai.pad = count;
1290       }
1291     }
1292     game->ai.max_y = game->current_level.landing_speed[game->ai.pad];
1293 
1294     // Calculate the half the difference between our current position
1295     //and the landing pad
1296     game->ai.target = game->current_level.landing_x[game->ai.pad] + 1;
1297     game->ai.difference = ( abs( game->ship.x - game->ai.target ) / 2 );
1298 
1299     // Decide if we're going left or right
1300     if( game->ai.target < game->ship.x ) {
1301       game->ai.difference = game->ship.x - game->ai.difference - 1;
1302       game->ai.direction = 0;
1303     }
1304     else {
1305       game->ai.difference = game->ship.x + game->ai.difference;
1306       game->ai.direction = 1;
1307     }
1308 
1309     //printf( "game->ai.difference: %d %d\n", game->ai.difference, game->ai.state );
1310   }
1311 
1312   // Stay under the final velocity
1313   if( game->ai.max_y < game->ship.y_vel ) {
1314     *down = 1;
1315   }
1316 
1317   /* --- state 1 & 2, main flight --- */
1318   if( game->ai.direction == 0 && game->ai.state < 3 ) {
1319 
1320     if( ( game->ai.state == 0 ) && ( game->ship.x > game->ai.difference ) ) {
1321       game->ai.state = 1;
1322     }
1323     if( ( game->ai.state == 1 ) && ( game->ship.x <= game->ai.difference ) ) {
1324       game->ai.state = 2;
1325     }
1326     if( ( game->ai.state == 2 ) && ( game->ship.x <= game->ai.target || game->ship.x_vel > 0 ) ) {
1327       game->ai.state = 3;
1328     }
1329 
1330     if( game->ai.state == 1 )
1331       *left = 1;
1332 
1333     if( game->ai.state == 2 )
1334       *right = 1;
1335 
1336     //printf( "game->ship.x1: %f %d %d %f\n", game->ship.x, game->ai.state, ( game->ship.x <= game->ai.target ), game->ai.target );
1337   }
1338 
1339   /* --- state 1 & 2, main flight --- */
1340   if( game->ai.direction == 1 && game->ai.state < 3 ) {
1341     if( (game->ai.state == 0) && (game->ship.x < game->ai.difference) ) {
1342       game->ai.state = 1;
1343     }
1344     if( (game->ai.state == 1) && (game->ship.x >= game->ai.difference) ) {
1345       game->ai.state = 2;
1346     }
1347     if( (game->ai.state == 2) && (game->ship.x >= game->ai.target || game->ship.x_vel < 0 ) ) {
1348       game->ai.state = 3;
1349     }
1350 
1351     if( game->ai.state == 1 )
1352       *right = 1;
1353     if( game->ai.state == 2 )
1354       *left = 1;
1355 
1356     //printf( "game->ship.x2: %f %d %d %f\n", game->ship.x, game->ai.state, ( game->ship.x >= game->ai.target ), game->ai.target );
1357 
1358   }
1359 
1360   /* --- state 3, bring x velocity close to zero --- */
1361   if( game->ai.state == 3 ) {
1362     if( game->ship.x_vel > 0.07 || game->ship.x_vel < -0.07 ) {
1363       if( game->ship.x_vel > 0 )
1364 	*left = 1;
1365       else
1366 	*right = 1;
1367     }
1368     else {
1369       game->ai.state = 4;
1370       game->ai.vdiff = game->ship.y + (( game->current_level.landing_y[game->ai.pad] - game->ship.y ) / 3);
1371     }
1372     //printf( "game->ship.x3: %f %d %d %f\n", game->ship.x, game->ai.state, ( game->ship.x >= game->ai.target ), game->ai.target );
1373   }
1374 
1375   /* --- state 4, close in on the landing pad --- */
1376   if( game->ai.state == 4 ) {
1377     if( ( game->ship.x < game->ai.target ) || ( game->ship.x > game->ai.target + 2 ) || game->ship.x_vel != 0.0 ) {
1378       if( game->ship.x > game->ai.target + 2 ) {
1379 	if( game->ship.x_vel > -0.07 )
1380 	  *left = 1;
1381 	//printf( "C1: x_vel=%f vel=%d left=%d right=%d\n", game->ship.x_vel, ( game->ship.x_vel > -0.07 ), *left, *right );
1382       }
1383       if( game->ship.x < game->ai.target ) {
1384 	if( game->ship.x_vel < 0.07 )
1385 	  *right = 1;
1386 	//printf( "C2: x_vel=%f vel=%d left=%d right=%d\n", game->ship.x_vel, ( game->ship.x_vel < 0.07 ), *left, *right );
1387       }
1388       //printf( "C3: x_vel=%f vel=%d left=%d right=%d\n", game->ship.x_vel, ( game->ship.x_vel < 0.07 ), *left, *right );
1389     }
1390 
1391     if( game->ship.y < (game->ai.vdiff + game->ship.y_vel ) )
1392       *down = 0;
1393 
1394     //printf( "4: game->ship.x=%f state=%d target=%f x_vel=%f y_vel=%f vdiff=%f\n", game->ship.x, game->ai.state, game->ai.target, game->ship.x_vel, game->ship.y_vel, game->ai.vdiff );
1395   }
1396 
1397   return;
1398 }
1399 
1400 
1401 
1402 /****************************************************************/
1403 /* ---------------------- gameloop ---------------------------- */
1404 
1405 
gameloop(Game * game)1406 void gameloop(Game *game){
1407   short int collision = 0;
1408   int down = 0;
1409   int left = 0;
1410   int right = 0;
1411   int count = 0;
1412   int engine_on=0;
1413   int engine_on_past=0;
1414   int won=0;
1415   int odd_even=0;
1416   int x;
1417   Uint8 *key_table;
1418   SDL_Event event;
1419   int pause = 0;
1420   int pressed = 0;
1421   int appressed = 0;
1422   char display_string[100];
1423 
1424   game->ai.state = 0;
1425 
1426 
1427   while (1) {
1428     /* zero out "show thrust" vars */
1429 
1430     down=0;
1431     left=0;
1432     right=0;
1433     engine_on=0;
1434     won = 0;
1435     odd_even++;
1436 
1437 
1438     /* gravity */
1439 
1440     if( !pause )
1441       game->ship.y_vel = game->ship.y_vel + game->gravity;
1442 
1443       /* read keyboard */
1444 
1445     SDL_PollEvent(&event);
1446 
1447     if (event.type == SDL_QUIT){
1448       exit(0);
1449     }
1450 
1451     key_table = SDL_GetKeyState(NULL);
1452 
1453     if (key_table[SDLK_ESCAPE]){
1454       options(game);
1455     }
1456 
1457     if (key_table[SDLK_RIGHT]){
1458       right = 1;
1459     }
1460 
1461     if (key_table[SDLK_LEFT]){
1462       left = 1;
1463     }
1464 
1465     if (key_table[SDLK_UP]){
1466       down = 1;
1467     }
1468 
1469     if (key_table[SDLK_a]){
1470       // toggle
1471       if( !appressed ) {
1472 	game->autopilot = (game->autopilot)?0:1;
1473 	appressed++;
1474 	if( game->autopilot == 1 ) {
1475 	  game->ai.state = 0;
1476 	}
1477       }
1478     }
1479     else{
1480       if( appressed ) {
1481 	appressed = 0;
1482       }
1483     }
1484 
1485     if (key_table[SDLK_q]){
1486       exit(0);
1487     }
1488 
1489     if( game->demo_mode && ( left || right || down || pause ) ) {
1490       collision = 1;
1491     }
1492 
1493     // Toggle pause on/off
1494     if( key_table[SDLK_p] ) {
1495       if( !pressed ) {
1496 	pause = (pause)?0:1;
1497 	pressed++;
1498 	if( pause ) {
1499 	  /* printf( "Pause pressed\n" ); */
1500 	  sprintf(display_string, "**PAUSED**");
1501 
1502 	  if (game->small_font > -1){
1503 	    DT_DrawText(display_string, game->screen, game->small_font, 300, 20);
1504 	  }
1505 	}
1506       }
1507     }
1508     else{
1509       if( pressed ) {
1510 	/* printf( "Pause released\n" ); */
1511 	pressed = 0;
1512       }
1513     }
1514 
1515     if (key_table[SDLK_q]){
1516       exit(0);
1517     }
1518 
1519     if( !pause ) {
1520 
1521       if( game->demo_mode || game->autopilot ) {
1522 	game->gravity = 0.05;
1523 	gameai( &left, &right, &down, game );
1524       }
1525 
1526       if( game->fuel > 0 ) {
1527 	if( right == 1 ) {
1528 	  game->ship.x_vel = game->ship.x_vel + 0.07;
1529 	  game->fuel = game->fuel - 1;
1530 	  engine_on=1;
1531 	}
1532 
1533 	if( left == 1) {
1534 	  game->ship.x_vel = game->ship.x_vel - 0.07;
1535 	  game->fuel = game->fuel - 1;
1536 	  engine_on=1;
1537 	}
1538 
1539 	if( down == 1 && game->fuel > 1 ) {
1540 	  game->ship.y_vel = game->ship.y_vel - 0.10;
1541 	  game->fuel = game->fuel - 2;
1542 	  engine_on=1;
1543 	}
1544 	else {
1545 	  down = 0;
1546 	}
1547       }
1548       else {
1549 	left = right = down = 0;
1550       }
1551 
1552 #ifndef NOSOUND
1553       if ( (engine_on == 1) && (! Mix_Playing(1) ) ){
1554 	Mix_PlayChannel(1, game->engine, 0);
1555       }
1556 
1557       if ( (engine_on == 0) && (engine_on_past == 1) ){
1558 	Mix_HaltChannel(1);
1559       }
1560 #endif
1561 
1562       engine_on_past = engine_on;
1563 
1564       /* update ship position */
1565 
1566       game->ship.x = game->ship.x + game->ship.x_vel;
1567       game->ship.y = game->ship.y + game->ship.y_vel;
1568 
1569       /* update rocket exhaust position */
1570 
1571       game->thrust.x = (game->ship.x + ( (game->ship.w - game->thrust.w) / 2));
1572       game->thrust.y = (game->ship.y + (game->ship.h -5));
1573 
1574       game->thrustb.x = (game->ship.x + ( (game->ship.w - game->thrust.w) / 2));
1575       game->thrustb.y = (game->ship.y + (game->ship.h -5));
1576 
1577       game->thrust_right.x = (game->ship.x - game->thrust_right.w) ;
1578       game->thrust_right.y = ( (game->ship.y + game->ship.h) - (game->thrust_right.h + 8) );
1579 
1580       game->thrust_left.x = (game->ship.x + game->ship.w) ;
1581       game->thrust_left.y = ( (game->ship.y + game->ship.h) - (game->thrust_left.h + 8) );
1582 
1583 
1584       /* draw screen */
1585 
1586       draw_sprite(game->screen, game->background);
1587       remaining_ships(game );
1588       draw_sprite(game->screen, game->ship);
1589       draw_sprite(game->screen, game->current_level.sprite);
1590 
1591 
1592       if( game->demo_mode ) {
1593 	sprintf(display_string, "**DEMO MODE - Press Arrow Keys To Exit**");
1594 	DT_DrawText(display_string, game->screen, game->small_font, 200, 20);
1595       }
1596 
1597       // Write in the landing pads as red if you're going too fast - if on
1598       if (game->opt_lp_warn){
1599 	for (count = 0; count < game->current_level.num_landings; count++){
1600 	  if( game->ship.y_vel > game->current_level.landing_speed[count] ) {
1601 
1602 	    for( x = game->current_level.landing_x[count];
1603 		 x < game->current_level.landing_x[count] + game->current_level.landing_w[count]; x++){
1604 
1605 	      DrawPixel(game->screen, 255, 0, 0, x, game->current_level.landing_y[count]);
1606 	      DrawPixel(game->screen, 255, 0, 0, x, game->current_level.landing_y[count]+1);
1607 	      DrawPixel(game->screen, 255, 0, 0, x, game->current_level.landing_y[count]+2);
1608 	    }
1609 	  }
1610 	}
1611       }
1612 
1613 
1614       if (right == 1){
1615 	draw_sprite(game->screen, game->thrust_right);
1616       }
1617 
1618       if (down == 1){
1619 	if ( (odd_even%2) == 0){
1620 	  draw_sprite(game->screen, game->thrust);
1621 	}
1622 	else{
1623 	  draw_sprite(game->screen, game->thrustb);
1624 	}
1625       }
1626 
1627       if (left == 1){
1628 	draw_sprite(game->screen, game->thrust_left);
1629       }
1630 
1631       /* display fuel  */
1632 
1633       draw_score(game, 1);
1634 
1635       /* flip screen so they show up */
1636 
1637       SDL_Flip(game->screen);
1638 
1639       /* check if off screen and way low */
1640 
1641       if (game->ship.y > YSIZE) {
1642 	explode(game->ship, game->current_level.sprite, game );
1643 
1644 	if( !game->ships_remaining ) {
1645 	  game->landing_pad = count;
1646 	  game->state = GAMEOVER;
1647 	  return;
1648 	}
1649 	else {
1650 	  game->landing_pad = count;
1651 	  game->ai.state = 0;
1652 	  game->state = LOST;
1653 	  return;
1654 	}
1655       }
1656 
1657       /* collision detection */
1658       if( !collision )
1659 	collision = collision_detect_perfect(game->ship, game->current_level.sprite);
1660 
1661       if (collision > 0){
1662 	collision = 0;
1663 	/* landing detection */
1664 
1665 	for (count = 0; count < game->current_level.num_landings; count++){
1666 
1667 
1668 	  if ( ((game->ship.x + 2) > game->current_level.landing_x[count])
1669 	       && ( ((game->ship.x - 2) + game->ship.w) <
1670 		    (game->current_level.landing_x[count] + game->current_level.landing_w[count]) )
1671 	       && (game->ship.y_vel < game->current_level.landing_speed[count])
1672 	       && (game->ship.x_vel <0.5) && (game->ship.x_vel > -0.5)){
1673 
1674 	    /* we landed! */
1675      	    won = 1;
1676 
1677 	    if( game->demo_mode ) {
1678 	      game->landing_pad = count;
1679 	      win(game, 0);
1680 	      game->state = GAMEOVER;
1681 	      return;
1682 	    }
1683 
1684 
1685 	    // Bonus ship every 10000 points
1686 	    if( (game->score / 10000) <
1687 		((game->score + game->current_level.landing_score[count]) / 10000 ) ) {
1688 	      // (MLH) This would be a good place to play a sound
1689 
1690 	      game->landing_pad = count;
1691 	      game->state = BONUS_SHIP;
1692 	      return;
1693 	    }
1694 
1695 	    game->landing_pad = count;
1696 	    game->state = WON;
1697 	    return;
1698 	  }
1699 
1700 	}
1701 
1702 	if (won == 0){
1703 
1704 	  /* didn't land */
1705 
1706 	  explode(game->ship, game->current_level.sprite, game );
1707 
1708 	  if( game->demo_mode ) {
1709 	    game->landing_pad = count;
1710 	    game->state = GAMEOVER;
1711 	    return;
1712 	  }
1713 
1714 	  if( !game->ships_remaining ) {
1715 	    game->landing_pad = count;
1716 	    game->state = GAMEOVER;
1717 	    return;
1718 	  }
1719 	  else {
1720 	    game->landing_pad = count;
1721 	    game->ai.state = 0;
1722 	    game->state = LOST;
1723 	    return;
1724 
1725 	  }
1726 
1727 	}
1728       }
1729     }
1730     else {
1731       SDL_Flip(game->screen);
1732     }
1733     /* timer - so that things run at an even speed regardless of cpu speed */
1734     frame_rate_limiter(game);
1735   }
1736 
1737 }
1738 
1739 
1740 
1741 
1742 /************************************************/
1743 /*******************   main   *******************/
1744 /************************************************/
1745 
1746 
main(int argc,char ** argv)1747 int main(int argc, char **argv) {
1748   char name[100];
1749   int count;
1750   char filename[100];
1751   Game game;
1752 
1753 
1754 #ifndef NOSOUND
1755   printf( "Sound active\n" );
1756 #endif
1757 
1758 #ifdef NOSOUND
1759   printf( "Sound disabled\n" );
1760 #endif
1761 
1762   game.demo_mode = 0;
1763   game.autopilot = 0;
1764 
1765   load_game(&game);
1766 
1767   game.score = 0;
1768   game.difficulty = 0;
1769   game.ships_remaining = (game.opt_num_lives - 1);
1770   game.gravity = 0.05;
1771 
1772   game.current_level.sprite.image = NULL;
1773   game.current_level.sprite.x = -1;
1774   game.background.image = NULL;
1775   game.background.x = -1;
1776   game.back_no = 0;
1777 
1778 
1779 
1780   /* initialize SDL */
1781   sprintf(filename, "%simages/win_icon.bmp", DATAPATH);
1782   game.screen = init_sdl(XSIZE, YSIZE, "Moon Lander", filename);
1783 
1784   printf("screen initialized\n");
1785 
1786   /* initialize sprites */
1787 
1788   sprintf(filename, "%simages/miniship2.bmp", DATAPATH);
1789   new_sprite(&(game.miniship), filename, 0, 0, 1, 0 );
1790 
1791   sprintf(filename, "%simages/newship.png", DATAPATH);
1792   new_sprite(&(game.ship), filename, XSIZE / 2, 1, 1, 0);
1793 
1794   sprintf(filename, "%simages/thrust1.png", DATAPATH);
1795   new_sprite(&(game.thrust), filename, 0, 0, 1, 0);
1796 
1797   sprintf(filename, "%simages/thrust2.png", DATAPATH);
1798   new_sprite(&(game.thrustb), filename, 0, 0, 1, 0);
1799 
1800   sprintf(filename, "%simages/thrust_left.bmp", DATAPATH);
1801   new_sprite(&(game.thrust_left), filename, 0, 0, 1, 0);
1802 
1803   sprintf(filename, "%simages/thrust_right.bmp", DATAPATH);
1804   new_sprite(&(game.thrust_right), filename, 0, 0, 1, 0);
1805 
1806   sprintf(filename, "%simages/logo.png", DATAPATH);
1807   new_sprite(&(game.logo), filename, 130, 25, 1, 0);
1808 
1809   sprintf(filename, "%simages/backgrounds/red_plain.jpg", DATAPATH);
1810   new_sprite(&(game.gameover_screen), filename, 0, 0, 0, 0);
1811 
1812   sprintf(filename, "%simages/magigames_steel.gif", DATAPATH);
1813   new_sprite(&(game.magigames), filename, 194, 410, 0, 0);
1814 
1815 #ifndef NOSOUND
1816 
1817 
1818   sprintf(filename, "%ssounds/Blaster_1.wav", DATAPATH);
1819   game.on = new_audio(filename);
1820   Mix_VolumeChunk(game.on, 20);
1821 
1822   sprintf(filename, "%ssounds/Retro_3.wav", DATAPATH);
1823   game.off = new_audio(filename);
1824   Mix_VolumeChunk(game.off, 20);
1825 
1826   sprintf(filename, "%ssounds/jet_lp.wav", DATAPATH);
1827   game.engine = new_audio(filename);
1828   Mix_VolumeChunk(game.engine, 40);
1829 
1830   sprintf(filename, "%ssounds/Space_Bubbles_2.wav", DATAPATH);
1831   game.new_life = new_audio(filename);
1832 
1833   sprintf(filename, "%ssounds/beep1b.wav", DATAPATH);
1834   game.ready= new_audio(filename);
1835   Mix_VolumeChunk(game.ready, 50);
1836 
1837   sprintf(filename, "%ssounds/honk.wav", DATAPATH);
1838   game.go = new_audio(filename);
1839   Mix_VolumeChunk(game.go, 100);
1840 
1841   sprintf(filename, "%ssounds/explosion2.wav", DATAPATH);
1842   game.explosion_a = new_audio(filename);
1843 
1844   sprintf(filename, "%ssounds/eagle_has_landed.wav", DATAPATH);
1845   game.eagle_landed = new_audio(filename);
1846   Mix_VolumeChunk(game.eagle_landed, 20);
1847 
1848 #endif
1849 
1850 
1851 
1852   /* intitalize timer */
1853 
1854   game.ActualTime = SDL_GetTicks();
1855   game.LastTime = game.ActualTime;
1856 
1857   /* load fonts */
1858 
1859   sprintf(filename, "%sfonts/ConsoleFont.bmp", DATAPATH);
1860   game.small_font = DT_LoadFont(filename, TRANS_FONT) ;
1861 
1862   sprintf(filename, "%sfonts/LargeFont.bmp", DATAPATH);
1863   game.big_font = DT_LoadFont(filename, TRANS_FONT) ;
1864 
1865 
1866   //printf("getting random level for first time\n");
1867   //random_level(&game);
1868 
1869   /* load explosion sprites here, because it takes a second or two*/
1870 
1871   for (count = 1; count < 26; count++){
1872     sprintf(name, "%simages/kablam/exp%02d.png",DATAPATH, count);
1873     new_sprite(&(game.explosion[count -1]), name, 0,0,1,200);
1874   }
1875 
1876   game.state = FRESHRUN;
1877 
1878 
1879 
1880   /* everything is now loaded up */
1881 
1882 
1883 
1884   while(1){
1885 
1886 #ifndef NOSOUND
1887     Mix_HaltChannel(1);
1888 #endif
1889 
1890     switch(game.state){
1891 
1892     case FRESHRUN:{
1893       game_over(&game, 1);
1894       break;
1895     }
1896 
1897 
1898     case GAMEOVER:{
1899       game_over(&game, 0);
1900       break;
1901     }
1902 
1903     case LOST:{
1904       new_round(&game, 0);
1905       gameloop(&game);
1906       break;
1907     }
1908 
1909     case WON:{
1910       win(&game, 0);
1911       new_round(&game, 1);
1912       gameloop(&game);
1913       break;
1914     }
1915 
1916     case BONUS_SHIP:{
1917       win(&game, 1);
1918       new_round(&game, 1);
1919       gameloop(&game);
1920       break;
1921     }
1922 
1923 
1924     case NEWGAME:{
1925       game.demo_mode = 0;
1926       new_round(&game, 3);
1927       gameloop(&game);
1928       break;
1929     }
1930 
1931     case AIGAME:{
1932       game.demo_mode = 1;
1933       new_round(&game, 3);
1934       gameloop(&game);
1935       break;
1936     }
1937 
1938     } /* end switch */
1939   }
1940 
1941 
1942   return(0);
1943 }
1944