1 /*
2  * XGalaga-SDL - a SDL port of XGalaga, clone of the game Galaga
3  * Copyright (c) 1995-1998 Joe Rumsey (mrogre@mediaone.net)
4  * Copyright (c) 2000 Andy Tarkinson <atark@thepipeline.net>
5  * Copyright (c) 2010 Frank Zago
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * 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., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "xgalaga.h"
28 
29 static struct torp torps[MAXTORPS];
30 static struct star stars[NUMSTARS];
31 static struct torp *first_etorp;
32 
33 static int convoyx = 0, convoymove = 1;
34 static int livecount = 0;
35 static int starspeed = 1;
36 static int attacking = 0, maxattacking, entering=0;
37 static int maxetorps = 5, numetorps=0;
38 static int plflash = 50;
39 #ifndef ORIGINAL_XGALAGA
40 static int shots = 0;
41 static int hits = 0;
42 #endif
43 static int mx;
44 
45 static struct W_Image *playerShip;
46 static struct W_Image *playerTorp;
47 static struct W_Image *enemyTorp;
48 static struct W_Image *shieldImage;
49 
50 #define convoy_x_pos(i) (convoyx+(20 * (i - 10 * (i/10))))
51 #define convoy_y_pos(i) (20 + (20*(i/10)))
52 
53 static int moves[16][2] = {
54     {0,-4},
55     {1,-4},
56     {3,-3},
57     {4,-1},
58     {4,0},
59     {4,1},
60     {3,3},
61     {1,4},
62     {0,4},
63     {-1,4},
64     {-3,3},
65     {-4,1},
66     {-4,0},
67     {-4,-1},
68     {-3,-3},
69     {-1,-4}
70 };
71 
xgal_exit(int v)72 static void xgal_exit(int v)
73 {
74 	sound_exit();
75 	SDL_Quit();
76     exit(v);
77 }
78 
79 #ifndef __WII__
print_usage(void)80 static void print_usage(void)
81 {
82     printf("XGalaga v%s\n"
83 		   "Copyright (c) 1995-1998 Joe Rumsey\n"
84 		   "Copyright (c) 2000 Andy Tarkinson\n"
85 		   "Copyright (c) 2010 Frank Zago\n"
86 		   "Contributions by Hermann Riedel\n"
87 		   "Command line options:\n"
88 		   "  -scores              Prints out the high score files and exits\n"
89 		   "  -nosound             Turn sound OFF\n"
90 		   "  -level <number>      Choose starting level (>= 1)\n"
91 		   "  -window              Start in windowed mode instead of fullscreen\n"
92 		   "  -winsize <WxH>       Window size (default 468 x 596)\n"
93 		   "\n"
94 		   "This game is free software, under the GPLv2\n"
95 		   "\n"
96 		   "Basic instructions:\n"
97 		   "  It's Galaga, you know how to play Galaga, stop bothering me.\n"
98 		   "\n"
99 		   "Keyboard commands:\n"
100 		   "  p - pauses\n"
101 		   "  q - end this game\n"
102 		   "  alt + enter - Toggle fullscreen - window\n",
103 		   VERSION);
104 }
105 #endif
106 
107 /*------------------stars-----------------*/
108 
109 /* Pick a random color, except black. */
get_random_star_color(void)110 static Uint32 get_random_star_color(void)
111 {
112 	switch(random() % 5) {
113 	case 0:
114 		return SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF);
115 	case 1:
116 		return SDL_MapRGB(screen->format, 0x00, 0xFF, 0x00);
117 	case 2:
118 		return SDL_MapRGB(screen->format, 0x00, 0xFF, 0xFF);
119 	case 3:
120 		return SDL_MapRGB(screen->format, 0xFF, 0x00, 0x00);
121 	default:
122 		return SDL_MapRGB(screen->format, 0xFF, 0xFF, 0x00);
123 	}
124 }
125 
init_stars(void)126 static void init_stars(void)
127 {
128     int i;
129 
130     for(i=0;i<NUMSTARS;i++) {
131         stars[i].x = random()%winwidth;
132         stars[i].y = random()%winheight;
133         stars[i].speed = (random()%3)+1;
134 		stars[i].pixel = get_random_star_color();
135     }
136 }
137 
do_stars(void)138 static void do_stars(void)
139 {
140     int i;
141 
142     if(wantStars) {
143 
144 		if (SDL_MUSTLOCK(screen))
145 			SDL_LockSurface(screen);
146 
147         for(i=0;i<NUMSTARS;i++) {
148 			stars[i].y+=stars[i].speed*((starspeed < 20) ? ABS(starspeed) : 20);
149             if(stars[i].y >= winheight) {
150                 stars[i].y-=winheight-ABS(starspeed);
151                 stars[i].x = random() % winwidth;
152 				stars[i].pixel = get_random_star_color();
153             }
154 			S_DrawPoint(stars[i].x, stars[i].y, stars[i].pixel);
155         }
156 #ifdef SHOW_SHIELD_BAR
157 	    if ((plshield > 0) || (shieldsleft > 0)) {
158 			int shieldcount = 0;
159 			int total_shields = (plshield + shieldsleft) * 19 / SHIELDTIME + 1;
160 			while (total_shields > 0) {
161 				shieldcount++;
162 				total_shields -= 19;
163 				S_DrawImage(winwidth - 20 * shieldcount, 0, 0, shieldImage);
164 			}
165 			while (total_shields < 0) {
166 				int column;
167 				column = winwidth - 20 * shieldcount - total_shields++;
168 				W_MakeLine(screen, column, 0, column, 20, S_Black);
169 				W_MakeLine(screen, column - 1, 0, column - 1, 20, S_Black);
170 			}
171 		}
172 #endif /* SHOW_SHIELD_BAR */
173 
174 		if (SDL_MUSTLOCK(screen))
175 			SDL_UnlockSurface(screen);
176     }
177 
178     if(starspeed != 1) {
179         char buf[20];
180 		int y;
181 
182         sprintf(buf, "LEVEL %d", level+1);
183 
184 		y = (winheight - SFont_TextHeight(fnt_big_red))/2;
185 		SFont_WriteCenter(fnt_big_red, y, buf);
186 
187 #ifndef ORIGINAL_XGALAGA
188 		if (shots > 0) {
189 			y += SFont_TextHeight(fnt_big_red) + 20;
190 
191 			sprintf(buf, "Torps: %d  Hits: %d (%d%%)", shots, hits, (100 * hits) / shots);
192 
193 			SFont_WriteCenter(fnt_reg_yellow, y, buf);
194 		}
195 #endif
196     }
197 }
198 
199 /*-------------------aliens---------------*/
200 
delete_etorps(void)201 static void delete_etorps(void)
202 {
203     struct torp *tmp;
204 
205     while(first_etorp) {
206         tmp = first_etorp->next;
207         free(first_etorp);
208         first_etorp = tmp;
209     }
210 }
211 
init_aliens(int level)212 static void init_aliens(int level)
213 {
214     int i;
215 
216     convoyx=0;
217     convoymove = 1;
218 
219     maxattacking = 1 + (level*2);
220     if(maxattacking > 30)
221         maxattacking = 30;
222     attacking = 0;
223     maxetorps = 10 + (level*5);
224     numetorps = 0;
225 
226     delete_etorps();
227     metaLevel = 1;
228     if (read_level(level) <= 0) {
229 		fprintf(stderr, "Error reading level %d\n", level);
230 		exit(0);
231     }
232 
233     for(i=0;i<MAXALIENS;i++) {
234         livecount++;
235         new_alien(i, &aliens[i]);
236     }
237 
238     for(i=0;i<MAXTORPS;i++)
239         torps[i].alive = 0;
240 }
241 
242 
undo_aliens(void)243 static void undo_aliens(void)
244 {
245     int i;
246 
247     for(i=0;i<MAXALIENS;i++) {
248         if(aliens[i].dying) {
249             aliens[i].alive = 0;
250             aliens[i].dying=0;
251         }
252     }
253 }
254 
do_escort(int i)255 static void do_escort(int i)
256 {
257     int fs = aliens[i].escorting;
258 
259     if(!aliens[fs].alive) {
260         aliens[i].escorting = -1;
261     } else if(aliens[fs].dir >= 0) {
262         aliens[i].dir = aliens[fs].dir;
263     } else {
264         aliens[i].x = 20 * (i - 10 * (i/10)) + convoyx + convoymove;
265         aliens[i].y = -10;
266         aliens[i].dir = -2;
267         aliens[i].path = -1;
268         aliens[i].steer = 2;
269         aliens[i].escorting = -1;
270     }
271 }
272 
273 static void
do_convoy(int i)274 do_convoy(int i)
275 {
276     aliens[i].x += convoymove;
277     if((entering == 0) &&
278        (attacking < maxattacking) &&
279        ((livecount < maxattacking) ||
280         ((random()%10000) < (level + 2 *(48-(livecount)))))) {
281         switch(random()%2) {
282         case 0:
283             path_dir(P_PEELLEFT, 0, &aliens[i].dir, &aliens[i].steer);
284             aliens[i].path = P_PEELLEFT;
285             break;
286         case 1:
287             path_dir(P_PEELRIGHT, 0, &aliens[i].dir, &aliens[i].steer);
288             aliens[i].path = P_PEELRIGHT;
289             break;
290         }
291         aliens[i].path_pos = 0;
292         attacking++;
293         if(i<10) { /* Flagship, grab escorts */
294             int e;
295             for(e=i+9;e<i+12;e++) {
296                 if(aliens[e].alive && aliens[e].dir == -1) {
297                     aliens[e].escorting = i;
298                 }
299             }
300         }
301     }
302 }
303 
new_etorp(int x,int y,int xs,int ys)304 static void new_etorp(int x, int y, int xs, int ys)
305 {
306     struct torp *t;
307 
308     t = malloc(sizeof(struct torp));
309     t->next = first_etorp;
310     if(t->next)
311         t->next->prev = t;
312     t->prev = NULL;
313     first_etorp = t;
314 
315     t->x = x;
316     t->y = y;
317     t->xspeed = xs;
318     t->yspeed = ys;
319     t->alive = 1;
320     t->frame = 0;
321     numetorps++;
322 }
323 
do_enter(int i)324 static void do_enter(int i)
325 {
326     int diffx, diffy;
327     int tc;
328 
329     if(aliens[i].enterdelay) {
330         aliens[i].enterdelay--;
331         return;
332     }
333 
334     if(aliens[i].path >= 0) {
335         aliens[i].x += moves[aliens[i].dir][0] + metaLevel * moves[aliens[i].dir][0]/2;
336         aliens[i].y += moves[aliens[i].dir][1] + metaLevel * moves[aliens[i].dir][1]/2;
337 
338         aliens[i].steer--;
339         if(aliens[i].steer <= 0) {
340             aliens[i].path_pos++;
341             enter_path_dir(aliens[i].path, aliens[i].path_pos, &aliens[i].dir, &aliens[i].steer);
342 			if(metaLevel > 1)
343 				aliens[i].steer = aliens[i].steer / (1 + ((metaLevel - 1) * .5));
344 			/*aliens[i].steer -= ((metaLevel - 1) * (aliens[i].steer / 3));*/
345 
346             if(aliens[i].dir < 0) {
347                 aliens[i].path = -1;
348             }
349         }
350         tc = TORPCHANCE - level/2 - weapon*5;
351         if(tc < 35) tc = 35;
352         if(numetorps < maxetorps && (!(random()%tc))) {
353             int xs, ys;
354 
355             /* could aim better, not sure it should! */
356 
357             if(aliens[i].x > plx + 200) {
358                 xs = -3;
359             } else if(aliens[i].x > plx + 100) {
360                 xs = -2;
361             } else if(aliens[i].x < plx - 200) {
362                 xs = 3;
363             } else if(aliens[i].x < plx - 100) {
364                 xs = 2;
365             } else {
366                 xs = 0;
367             }
368             ys = (ETORPSPEED+level/5) - ABS(xs);
369             new_etorp(aliens[i].x, aliens[i].y, xs, ys);
370         }
371     } else {
372         diffx = ABS(convoy_x_pos(i) - aliens[i].x);
373         diffy = ABS(convoy_y_pos(i) - aliens[i].y);
374         if(diffy< 4 + (metaLevel * 2)) {
375             aliens[i].y = convoy_y_pos(i);
376             if(diffx < 4 + (metaLevel * 2)) {
377                 aliens[i].x = convoy_x_pos(i);
378                 aliens[i].dir = -1;
379                 aliens[i].entering = 0;
380                 return;
381             }
382             aliens[i].dir = 0;
383             if(convoy_x_pos(i) > aliens[i].x)
384                 aliens[i].dir = 4;
385             else
386                 aliens[i].dir = 12;
387         } else {
388 			if(convoy_y_pos(i) < aliens[i].y) {
389 				if(diffx < 4 + (metaLevel * 2)) {
390 					aliens[i].x = convoy_x_pos(i);
391 					aliens[i].dir = 0;
392 				} else {
393 					if(convoy_x_pos(i) > aliens[i].x)
394 						aliens[i].dir = 2;
395 					else
396 						aliens[i].dir = 14;
397 				}
398 			} else {
399 				if(diffx < 4 + (metaLevel * 2)) {
400 					aliens[i].x = convoy_x_pos(i);
401 					aliens[i].dir = 8;
402 				} else {
403 					if(convoy_x_pos(i) > aliens[i].x)
404 						aliens[i].dir = 6;
405 					else
406 						aliens[i].dir = 10;
407 				}
408 			}
409         }
410         aliens[i].x += moves[aliens[i].dir][0] + metaLevel * moves[aliens[i].dir][0]/2;
411         aliens[i].y += moves[aliens[i].dir][1] + metaLevel * moves[aliens[i].dir][1]/2;
412     }
413 }
414 
do_aliens(void)415 static void do_aliens(void)
416 {
417     int i, j;
418     int tc;
419 
420     if(gstate != PAUSED) {
421         convoyx += convoymove;
422         if(convoyx <= 0) {
423             convoyx=0;
424             convoymove = -convoymove;
425         } else if(convoyx >= (winwidth-180)) {
426             convoyx = winwidth - 180;
427             convoymove = -convoymove;
428         }
429     }
430 
431     livecount=0; attacking = 0;
432     for(i=0, livecount=0, entering=0; i < MAXALIENS; i++) {
433         if(aliens[i].alive) {
434             livecount++;
435             if(aliens[i].dir >= 0 && aliens[i].escorting < 0 && !(aliens[i].entering))
436                 attacking++;
437             if(aliens[i].entering)
438                 entering++;
439         }
440     }
441 
442     for(i=0; i < MAXALIENS; i++) {
443         if(aliens[i].alive) {
444             if (gstate != PAUSED) {
445                 if(aliens[i].escorting >= 0) {
446                     do_escort(i);
447                 }
448 
449                 if(aliens[i].entering) {
450                     do_enter(i);
451                 } else if(aliens[i].dir == -1) {
452                     do_convoy(i);
453                 } else if(aliens[i].dir == -2) {
454                     aliens[i].x += convoymove;
455                     aliens[i].y+=2;
456                     if(aliens[i].y >= 20 + (20*(i/10))) {
457                         aliens[i].y = 20 + (20*(i/10));
458                         aliens[i].dir = -1;
459                     }
460                 } else {
461                     aliens[i].x += moves[aliens[i].dir][0];
462                     aliens[i].y += moves[aliens[i].dir][1];
463                     if(aliens[i].x > winwidth+20)
464                         aliens[i].x = -20;
465                     else if(aliens[i].x < -20)
466                         aliens[i].x = winwidth+20;
467 
468                     if(aliens[i].y > winheight) {
469                         aliens[i].x = 20 * (i - 10 * (i/10)) + convoyx + convoymove;
470                         aliens[i].y = -30;
471                         aliens[i].dir = -2;
472                         aliens[i].path = -1;
473                         aliens[i].steer = 2;
474                         aliens[i].escorting = -1;
475                         attacking--;
476                         if(i < 10) {
477                             for(j=i+9;j<i+12;j++)
478                                 aliens[j].escorting = -1;
479                         }
480                     } else if(aliens[i].y < 0) {
481                         aliens[i].dir = 8;
482                     }
483 
484                     if(aliens[i].escorting < 0) {
485                         aliens[i].steer--;
486                         if(aliens[i].steer <= 0) {
487                             if(aliens[i].path >= 0) {
488                                 int lastdir=aliens[i].dir;
489 
490                                 aliens[i].path_pos++;
491                                 path_dir(aliens[i].path, aliens[i].path_pos, &aliens[i].dir, &aliens[i].steer);
492                                 if(aliens[i].dir < 0) {
493                                     aliens[i].dir = lastdir;
494                                 newpath:
495                                     switch(random()%8) {
496                                     case 0:
497                                         start_path(P_LOOP, &aliens[i]);
498                                         break;
499                                     case 1:
500                                         start_path(P_SWOOP1, &aliens[i]);
501                                         break;
502                                     case 2:
503                                         start_path(P_SWOOP2, &aliens[i]);
504                                         break;
505                                     case 3:
506                                         start_path(P_ZIGZAG, &aliens[i]);
507                                         break;
508                                     case 4:
509                                         start_path(P_LOOP2, &aliens[i]);
510                                         break;
511                                     case 5:
512                                         start_path(P_SPIN, &aliens[i]);
513                                         break;
514                                     case 6:
515                                         start_path(P_LEFTDIAG, &aliens[i]);
516                                         break;
517                                     case 7:
518                                         start_path(P_RIGHTDIAG, &aliens[i]);
519                                         break;
520                                     default:
521                                         aliens[i].steer = TURNSPEED;
522                                         aliens[i].path = -1;
523                                     }
524                                     if((aliens[i].path < 0) || (aliens[i].steer < 0)) {
525                                         goto newpath;
526                                     }
527                                 }
528                             } else {
529                                 if(random()%2) {
530                                     aliens[i].dir++;
531                                     if(aliens[i].dir > 15)
532                                         aliens[i].dir = 0;
533                                 } else {
534                                     aliens[i].dir--;
535                                     if(aliens[i].dir < 0)
536                                         aliens[i].dir = 15;
537                                 }
538                                 aliens[i].steer = TURNSPEED;
539                             }
540                         }
541                     }
542                     tc = TORPCHANCE - level/2 - weapon*5;
543                     if(tc < 35) tc = 35;
544 
545                     if(numetorps < maxetorps && (!(random()%tc))) {
546                         int xs, ys;
547 
548                         /* could aim better, not sure it should! */
549 
550                         if(aliens[i].x > plx + 200) {
551                             xs = -3;
552                         } else if(aliens[i].x > plx + 100) {
553                             xs = -2;
554                         } else if(aliens[i].x < plx - 200) {
555                             xs = 3;
556                         } else if(aliens[i].x < plx - 100) {
557                             xs = 2;
558                         } else {
559                             xs = 0;
560                         }
561                         ys = (ETORPSPEED+level/5) - ABS(xs);
562                         new_etorp(aliens[i].x, aliens[i].y, xs, ys);
563                     }
564                 }
565                 S_DrawImage(aliens[i].x-(aliens[i].shape->width/2),
566                             aliens[i].y-(aliens[i].shape->height/2),
567                             aliens[i].dir < 0 ? 0 : aliens[i].dir,
568 							aliens[i].shape);
569             } else {
570 				/* paused */
571                 S_DrawImage(aliens[i].x-(aliens[i].shape->width/2),
572                             aliens[i].y-(aliens[i].shape->height/2),
573                             aliens[i].dir < 0 ? 0 : aliens[i].dir,
574 							aliens[i].shape);
575             }
576         }
577     }
578     if (livecount == 0 && (gstate != PAUSED)) {
579         starspeed++;
580         if(starspeed == 2)
581             play_sound(SND_WARP);
582         if(starspeed >= 120) {
583             starspeed = -20;
584         } else if(starspeed == 1) {
585             init_aliens(++level);
586             gotlemon = 0;
587             starspeed = 1;
588             numtorps=0;
589         }
590     }
591 }
592 
593 /*------------------player----------------*/
init_player(void)594 static void init_player(void)
595 {
596     int i;
597     for(i=0;i<MAXTORPS;i++)
598         torps[i].alive=0;
599 }
600 
new_torp(int x,int y,int xs,int ys)601 static void new_torp(int x, int y, int xs, int ys)
602 {
603     int i;
604 
605     for(i=0;i<maxtorps;i++) {
606         if(!torps[i].alive) {
607             torps[i].x = x;
608             torps[i].y = y;
609             torps[i].alive = 1;
610             torps[i].xspeed = xs;
611             torps[i].yspeed = ys;
612             numtorps++;
613             play_sound(SND_FIRETORP);
614             return;
615         }
616     }
617 }
618 
do_torps(void)619 static void do_torps(void)
620 {
621     int i,j,k, ne;
622 
623     for(i=0;i<MAXTORPS;i++) {
624         if(torps[i].alive) {
625             if(gstate != PAUSED) {
626                 torps[i].y += torps[i].yspeed;
627                 torps[i].x += torps[i].xspeed;
628                 torps[i].frame++;
629                 for(j=0;j<MAXALIENS;j++) {
630                     if(aliens[j].alive && !aliens[j].dying &&
631                        (ABS(torps[i].x - aliens[j].x) < 8) &&
632                        ((ABS(torps[i].y - aliens[j].y) < 8) ||
633                         (ABS((torps[i].y + torps[i].yspeed/2)-aliens[j].y) < 8))) {
634                         aliens[j].dying = 1;
635                         if(aliens[j].dir >= 0)
636                             attacking--;
637 
638                         torps[i].alive=0;
639                         numtorps--;
640                         if(j >= 10) {
641                             if(aliens[j].dir < 0)
642                                 score += 50;
643                             else {
644                                 score += (6-(j/10))*100;
645                                 if(!(random()%(gotlemon ? 3 : PRIZECHANCE)))
646                                     new_prize(aliens[j].x, aliens[j].y);
647                             }
648                             new_explosion(aliens[j].x, aliens[j].y, 0);
649                         } else {
650                             if(aliens[j].dir < 0)
651                                 score += 200;
652                             else {
653                                 ne=0; /* count how many escorts */
654                                 for(k = j+9;k < j+12; k++) {
655                                     if(aliens[k].escorting == j)
656                                         ne++;
657                                 }
658                                 score_flagship(aliens[j].x, aliens[j].y, ne);
659                             }
660                             new_explosion(aliens[j].x, aliens[j].y, 1);
661                         }
662                         goto skip;
663                     }
664                 }
665                 if(torps[i].y < -torps[i].yspeed ||
666                    torps[i].x < ABS(torps[i].xspeed) ||
667                    torps[i].x > winwidth-ABS(torps[i].xspeed)) {
668                     torps[i].alive = 0;
669                     numtorps--;
670                 } else
671                     S_DrawImage(torps[i].x-(playerTorp->width/2),
672                                 torps[i].y-(playerTorp->height/2),
673                                 torps[i].frame, playerTorp);
674             skip: ;
675             } else {
676 				/* paused */
677                 S_DrawImage(torps[i].x-(playerTorp->width/2),
678                             torps[i].y-(playerTorp->height/2),
679                             torps[i].frame, playerTorp);
680             }
681         }
682     }
683 }
684 
do_etorps(void)685 static void do_etorps(void)
686 {
687     struct torp *t = first_etorp, *nextt;
688 
689     while(t) {
690         nextt=t->next;
691         if(t->alive) {
692             if(gstate != PAUSED) {
693                 t->y+=t->yspeed;
694                 t->x+=t->xspeed;
695                 t->frame++;
696                 if(t->y > winheight || t->x < 0 || t->x > winwidth) {
697                     if(t->next)
698                         t->next->prev = t->prev;
699                     if(t->prev)
700                         t->prev->next = t->next;
701                     if(t == first_etorp)
702                         first_etorp = t->next;
703                     free(t);
704                     numetorps--;
705                 } else if(!pldead && !plflash && !plshield &&
706                           (ABS(t->x - plx) < 8) &&
707                           (ABS(t->y - (winheight - (int)playerShip->height / 2)) < 8)) { /* DEAD! */
708                     pldead = 1;
709                     new_explosion(plx, winheight - playerShip->height/2, 2);
710                 } else {
711                     S_DrawImage(t->x-(enemyTorp->width/2),
712                                 t->y-(enemyTorp->height/2),
713                                 t->frame, enemyTorp);
714                 }
715             } else {
716                 S_DrawImage(t->x-(enemyTorp->width/2),
717                             t->y-(enemyTorp->height/2),
718                             t->frame, enemyTorp);
719             }
720         }
721         t = nextt;
722     }
723 }
724 
start_game(void)725 static void start_game(void)
726 {
727 	gstate = PLAYING;
728 	maxtorps = MINTORPS;
729 	weapon = 0;
730 	movespeed = MINSPEED;
731 	ships=2;
732 #ifdef ACTIVATED_SHIELD
733 	shieldsleft = STARTSHIELDS;
734 	shieldon = 0;
735 #else
736 	shieldsleft = 0;
737 #endif
738 	level=startLevel;  /* change made here */
739 	init_aliens(level);
740 	gotlemon = 0;
741 	pldead = 0;
742 	score = 0;
743 	nextBonus = 20000;
744 	plx = winwidth/2;
745 	mx = plx;
746 }
747 
do_player(int but)748 static void do_player(int but)
749 {
750     static int torpok;
751 #ifdef ENABLE_MACHINE_GUN
752     static int shotside = 0;
753 #endif
754     SDL_Event event;
755     static int keys = 0;
756 
757     if (gstate == INTRO) {
758         while(SDL_PollEvent(&event)) {
759 
760             switch(event.type) {
761 			case SDL_QUIT:
762 				xgal_exit(0);
763 				break;
764 
765 			case SDL_JOYBUTTONDOWN:
766 				/* Test buttons 0 to 3. */
767 				if (event.jbutton.button <= 3)
768 					start_game();
769 #ifdef __WII__
770 				else if ((event.jbutton.button == 6) ||
771 						 (event.jbutton.button == 19)) {
772 					/* Home button on wiimote or classic controller */
773 					xgal_exit(0);
774 				}
775 #endif
776 				break;
777 
778             case SDL_KEYDOWN:
779                 switch(event.key.keysym.sym) {
780 				case SDLK_ESCAPE:
781                 case SDLK_q:
782                     xgal_exit(0);
783                     break;
784 
785 				case SDLK_SPACE:
786 					start_game();
787 					break;
788 
789 				case SDLK_RETURN:
790 					if (event.key.keysym.mod & (KMOD_LALT | KMOD_RALT))
791 						toggle_fullscreen();
792 					break;
793 
794                 case SDLK_s:       /* toggle sound on the title screen */
795                     playSounds = !playSounds;
796 					return;     /* this key must not start the game */
797 					break;
798 
799 				case SDLK_RIGHT:
800 					title_page_next();
801 					break;
802 
803 				case SDLK_LEFT:
804 					title_page_prev();
805 					break;
806 
807 				default:
808                     return;     /* unhandled key must not cause any action */
809 					break;
810                 }
811 
812 				break;
813 
814             default:
815 				break;
816             }
817         }
818         return;
819     }
820 	else if (gstate == GETTING_NAME) {
821 
822         while(SDL_PollEvent(&event)) {
823             switch(event.type) {
824 			case SDL_QUIT:
825 				xgal_exit(0);
826 				break;
827 
828 #ifdef __WII__
829 			case SDL_JOYBUTTONDOWN:
830 				if ((event.jbutton.button == 6) ||
831 					(event.jbutton.button == 19)) {
832 					/* Home button on wiimote or classic controller */
833 					xgal_exit(0);
834 				}
835 				break;
836 #endif
837 
838             case SDL_KEYDOWN:
839                 if (score_key(event.key.keysym.sym))
840                     continue;
841 			}
842 		}
843 		return;
844 	}
845 
846 
847     while(SDL_PollEvent(&event)) {
848 
849         switch(event.type) {
850 		case SDL_QUIT:
851 			xgal_exit(0);
852 			break;
853 
854         case SDL_KEYUP:
855             switch(event.key.keysym.sym) {
856             case SDLK_RIGHT:
857                 keys &= ~RIGHTKEY;
858                 break;
859 
860             case SDLK_LEFT:
861                 keys &= ~LEFTKEY;
862                 break;
863 
864             case SDLK_SPACE:
865                 keys &= ~FIREKEY;
866 				break;
867 
868 #ifdef ACTIVATED_SHIELD
869 			case SDLK_x:
870 				shieldsleft += plshield;
871 				plshield = 0;
872 				shieldon = 0;
873 				break;
874 #endif
875 			default:
876 				break;
877             }
878             break;
879 
880         case SDL_KEYDOWN:
881             switch(event.key.keysym.sym) {
882             case SDLK_RIGHT:
883                 keys |= RIGHTKEY;
884                 break;
885 
886             case SDLK_LEFT:
887                 keys |= LEFTKEY;
888                 break;
889 
890             case SDLK_SPACE:
891                 keys |= FIREKEY;
892 				break;
893 
894 #ifdef ACTIVATED_SHIELD
895 			case SDLK_x:
896 				plshield += shieldsleft;
897 				shieldsleft = 0;
898 				shieldon = 1;
899 				break;
900 #endif
901 
902             case SDLK_g:
903                 if(!pldead  && (gstate != PAUSED)) {
904                     new_explosion(plx, winheight - ((playerShip->height)/2), 2);
905                     ships = 0;
906                     pldead = 1;
907                 }
908 				break;
909 
910             case SDLK_q:
911                 xgal_exit(0);
912 				break;
913 
914             case SDLK_p:
915 				if (gstate == PAUSED)
916 					gstate = PLAYING;
917 				else
918 					gstate = PAUSED;
919 				break;
920 
921             case SDLK_s:
922                 playSounds = !playSounds;
923 				break;
924 
925 #ifdef IM_A_BIG_FAT_CHEATER
926             case SDLK_i:
927                 if(plflash >= 0)
928                     plflash = -2;
929                 else
930                     plflash = 0;
931 				break;
932 
933             case SDLK_l:
934 			{
935 				int i;
936 				for(i=0;i<MAXALIENS;i++)
937 					aliens[i].alive=0;
938 				if(starspeed != 1)
939 					level++;
940 			}
941 			break;
942 
943             case SDLK_c:
944                 score+= BONUSSHIPSCORE;
945 				break;
946 
947             case SDLK_h:
948                 plshield = SHIELDTIME;
949 				play_sound(SND_SHIELD);
950 				break;
951 
952             case SDLK_w:
953                 weapon++;
954 				if(weapon == NUMWEAPONS)
955 					weapon=0;
956 				break;
957 
958             case SDLK_t:
959                 maxtorps++;
960 				if(maxtorps > MAXTORPS)
961 					maxtorps = MINTORPS;
962 				break;
963 
964 #endif /* IM_A_BIG_FAT_CHEATER */
965 
966 			case SDLK_RETURN:
967 				if (event.key.keysym.mod & (KMOD_LALT | KMOD_RALT))
968 					toggle_fullscreen();
969 				break;
970 
971             default:
972                 break;
973             }
974 			break;
975 
976 		case SDL_JOYBUTTONDOWN:
977 			/* Test buttons 0 to 3. */
978 			if (event.jbutton.button <= 3)
979 				keys |= FIREKEY;
980 #ifdef __WII__
981 			else if ((event.jbutton.button == 6) ||
982 					 (event.jbutton.button == 19)) {
983 				/* Home button on wiimote or classic controller */
984 				xgal_exit(0);
985 			}
986 #endif
987 			break;
988 
989 		case SDL_JOYBUTTONUP:
990 			/* Test buttons 0 to 3. */
991 			if (event.jbutton.button <= 3)
992 				keys &= ~FIREKEY;
993 			break;
994 
995 		case SDL_JOYHATMOTION:
996 			if (event.jhat.value & SDL_HAT_RIGHT) {
997 				keys |= RIGHTKEY;
998 				keys &= ~LEFTKEY;
999 			}
1000 			else if (event.jhat.value & SDL_HAT_LEFT) {
1001 				keys |= LEFTKEY;
1002 				keys &= ~RIGHTKEY;
1003 			}
1004 			else
1005 				keys &= ~(LEFTKEY | RIGHTKEY);
1006 			break;
1007 
1008 		case SDL_JOYAXISMOTION:
1009 			/* My gamepad has 2 analog input, with X being axis 0 and 3. */
1010 			if (event.jaxis.axis == 0 || event.jaxis.axis == 3)  {
1011 				if (event.jaxis.value < -10000) {
1012 					keys |= LEFTKEY;
1013 					keys &= ~RIGHTKEY;
1014 				}
1015 				else if (event.jaxis.value > 10000) {
1016 					keys |= RIGHTKEY;
1017 					keys &= ~LEFTKEY;
1018 				}
1019 				else
1020 					keys &= ~(LEFTKEY | RIGHTKEY);
1021 			}
1022 			break;
1023         }
1024     }
1025 
1026     if (gstate != PAUSED) {
1027         torpok--;
1028 
1029 		if(keys & LEFTKEY)
1030 			mx = 0;
1031 		else if(keys & RIGHTKEY)
1032 			mx = winwidth;
1033 		else
1034 			mx = plx;
1035 
1036 		if(keys & FIREKEY)
1037 			but = 1;
1038 		else
1039 			but = 0;
1040 
1041         if(pldead) {
1042             pldead++;
1043             if(pldead >= 100) {
1044                 if(ships<=0) {
1045                     if(check_score(score)) {
1046 #ifdef USE_REAL_NAMES
1047                         add_score(getUsersFullName(), score);
1048                         title_page = 1; pagetimer = 300;
1049 						gstate = INTRO;
1050 #else
1051 						gstate = GETTING_NAME;
1052 #endif
1053                     } else {
1054 						gstate = INTRO;
1055 					}
1056                 } else {
1057 #ifdef DISABLE_RESET_ON_DEATH
1058                     ships--;
1059                     maxtorps--;
1060                     if (maxtorps < MINTORPS)
1061                     	maxtorps = MINTORPS;
1062                     switch (weapon)
1063                     {
1064 					case SINGLESHOT:
1065 						if (maxtorps < 3)
1066 						{
1067 							maxtorps = 3;
1068 							weapon = SINGLESHOT;
1069 						}
1070 						break;
1071 					case DOUBLESHOT:
1072 						if (maxtorps < 4)
1073 						{
1074 							maxtorps = 4;
1075 						}
1076 						break;
1077 					case SPREADSHOT:
1078 						if (maxtorps < 5)
1079 						{
1080 							maxtorps = 5;
1081 						}
1082 						break;
1083 					case TRIPLESHOT:
1084 						if (maxtorps < 6)
1085 						{
1086 							maxtorps = 6;
1087 						}
1088 						break;
1089 					case MACHINEGUN:
1090 						if (maxtorps < 3)
1091 						{
1092 							maxtorps = 3;
1093 						}
1094 						break;
1095 					}
1096 #else
1097                     ships--;
1098                     maxtorps = MINTORPS;
1099                     weapon = 0;
1100                     movespeed = MINSPEED;
1101 #endif /* DISABLE_RESET_ON_DEATH */
1102                     pldead = 0;
1103                     plflash = 50;
1104                     plx = winwidth/2;
1105                 }
1106             }
1107             return;
1108         }
1109 
1110         if(but && torpok <= 0 && (starspeed == 1)) {
1111             switch(weapon) {
1112             case SINGLESHOT:
1113                 if(numtorps < maxtorps)
1114                     new_torp(plx, winheight - playerShip->height, 0, -TORPSPEED);
1115 				torpok = TORPDELAY;
1116                 break;
1117             case DOUBLESHOT:
1118                 if(numtorps < maxtorps-1) {
1119                     new_torp(plx-5, winheight - playerShip->height, 0, -TORPSPEED);
1120                     new_torp(plx+5, winheight - playerShip->height, 0, -TORPSPEED);
1121 					torpok = TORPDELAY;
1122                 }
1123                 break;
1124             case TRIPLESHOT:
1125                 if(numtorps < maxtorps-2) {
1126                     new_torp(plx-5, winheight - playerShip->height, -2, 1-TORPSPEED);
1127                     new_torp(plx,   winheight - playerShip->height, 0,   -TORPSPEED);
1128                     new_torp(plx+5, winheight - playerShip->height, 2, 1-TORPSPEED);
1129 					torpok = TORPDELAY;
1130                 }
1131                 break;
1132 #ifdef ENABLE_SPREAD_SHOT
1133             case SPREADSHOT:
1134             	if (numtorps == 0)
1135                 {
1136 					if ((maxtorps % 2) == 1)
1137 						new_torp(plx, winheight - playerShip->height, 0, -TORPSPEED*1.15);
1138 					else
1139 					{
1140 						new_torp(plx - 5, winheight - playerShip->height, 0, -TORPSPEED*1.15);
1141 						new_torp(plx + 5, winheight - playerShip->height, 0, -TORPSPEED*1.15);
1142 					}
1143 					if (maxtorps > 2)
1144 					{
1145 						new_torp(plx, winheight - playerShip->height - 15, -2, -TORPSPEED*1.15);
1146 						new_torp(plx, winheight - playerShip->height - 15, 2, -TORPSPEED*1.15);
1147 					}
1148 					if (maxtorps > 4)
1149 					{
1150 						new_torp(plx, winheight - playerShip->height - 25, -4, -TORPSPEED*1.15);
1151 						new_torp(plx, winheight - playerShip->height - 25, 4, -TORPSPEED*1.15);
1152 					}
1153 					if (maxtorps > 6)
1154 					{
1155 						new_torp(plx, winheight - playerShip->height - 35, -6, -TORPSPEED*1.15);
1156 						new_torp(plx, winheight - playerShip->height - 35, 6, -TORPSPEED*1.15);
1157 					}
1158 					if (maxtorps > 8)
1159 					{
1160 						new_torp(plx, winheight - playerShip->height - 50, -8, -TORPSPEED*1.15);
1161 						new_torp(plx, winheight - playerShip->height - 50, 8, -TORPSPEED*1.15);
1162 					}
1163 					if (maxtorps > 10)
1164 					{
1165 						new_torp(plx, winheight - playerShip->height - 60, -10, -TORPSPEED*1.15);
1166 						new_torp(plx, winheight - playerShip->height - 60, 10, -TORPSPEED*1.15);
1167 					}
1168 					torpok = TORPDELAY;
1169 				}
1170 				break;
1171 #endif /* ENABLE_SPREAD_SHOT */
1172 #ifdef ENABLE_MACHINE_GUN
1173             case MACHINEGUN:
1174 				if(numtorps < maxtorps)
1175 				{
1176 					shotside = (shotside == -15) ? 15 : -15;
1177 					new_torp(plx + shotside, winheight - playerShip->height, 0, -TORPSPEED * 1.3);
1178 					torpok = TORPDELAY - 2;
1179 				}
1180 				break;
1181 #endif /* ENABLE_MACHINE_GUN */
1182 			}
1183 		}
1184 
1185 
1186         if(!but)
1187             torpok=0;
1188 
1189         if((mx/movespeed) > (plx/movespeed))
1190             plx+=movespeed;
1191         else if((mx/movespeed) < (plx/movespeed))
1192             plx-=movespeed;
1193 #ifdef ENABLE_SHIP_WRAP
1194 
1195         if(plx < 10)
1196         	plx=winwidth - 10;
1197         if(plx > winwidth - 10)
1198 			plx=10;
1199 #else
1200 
1201         if(plx < playerShip->width/2)
1202             plx=playerShip->width/2;
1203         if(plx> winwidth - playerShip->width/2)
1204             plx=winwidth - playerShip->width/2;
1205 #endif
1206 
1207         if(plflash > 0)
1208             plflash--;
1209         if(!(plflash % 2))
1210             S_DrawImage(plx-(playerShip->width/2), winheight - playerShip->height, counter, playerShip);
1211         if(plshield > 0)
1212             plshield--;
1213         if(plshield && ((plshield > SHIELDTIME/4) || plshield % 2)) {
1214             S_DrawImage(plx-(shieldImage->width/2), winheight - shieldImage->height - 3, 0, shieldImage);
1215         }
1216     } else if (!pldead) { /* paused */
1217         S_DrawImage(plx-(playerShip->width/2), winheight - playerShip->height, counter, playerShip);
1218     }
1219 }
1220 
init_fonts(void)1221 static int init_fonts(void)
1222 {
1223 	fnt_reg_green = SFont_InitFont(F_REG_GREEN);
1224 	fnt_reg_cyan = SFont_InitFont(F_REG_CYAN);
1225 	fnt_reg_yellow = SFont_InitFont(F_REG_YELLOW);
1226 	fnt_reg_red = SFont_InitFont(F_REG_RED);
1227 	fnt_reg_grey = SFont_InitFont(F_REG_GREY);
1228 	fnt_big_red = SFont_InitFont(F_BIG_RED);
1229 
1230     if (!fnt_reg_green || !fnt_reg_cyan || !fnt_reg_yellow ||
1231 		!fnt_reg_red || !fnt_reg_grey || !fnt_big_red)
1232 		return 0;
1233 
1234 	return 1;
1235 }
1236 
main(int argc,char * argv[])1237 int main(int argc, char *argv[])
1238 {
1239     int ac;
1240     int but;
1241 
1242 	but = 0;
1243 
1244 #ifndef __WII__
1245     for(ac = 1; ac < argc; ac++) {
1246         if(*argv[ac] == '-') {
1247             int w, h;
1248             if(strcmp(argv[ac], "-scores") == 0) {
1249                 print_scores();
1250                 exit(0);
1251             } else if (strcmp(argv[ac], "-nosound") == 0) {
1252                 playSounds = 0;
1253 				/* '-level' option defined here */
1254             } else if (strcmp(argv[ac], "-level") == 0 && (ac+1 < argc)
1255                        && atoi(argv[ac+1]) >= 1)
1256             {
1257                 int nlev;
1258                 nlev = atoi(argv[ac+1]);
1259                 if (nlev > 15 ) nlev = 15;
1260                 startLevel = nlev;
1261                 ac++;
1262             } else if (strcmp(argv[ac], "-nostars") == 0) {
1263                 wantStars = 0;
1264             } else if (strcmp(argv[ac], "-window") == 0) {
1265                 fullscreen = 0;
1266             } else if ((strcmp(argv[ac], "-winsize") == 0) && (++ac < argc) &&
1267                        (sscanf(argv[ac], "%dx%d", &w, &h) == 2)) {
1268                 winwidth  = w;
1269                 winheight = h;
1270             } else {
1271                 print_usage();
1272                 exit(0);
1273             }
1274         } else {
1275             print_usage();
1276             exit(0);
1277         }
1278     }
1279 #endif
1280 
1281     S_Initialize(fullscreen);
1282 
1283     SDL_WM_SetCaption("XGalaga (SDL)", NULL);
1284 
1285 	if (!loadAllImages()) {
1286 		fprintf(stderr, "Cannot load one or more images\n");
1287 		return -1;
1288 	}
1289 
1290 	if (!init_fonts()) {
1291 		fprintf(stderr, "Invalid font\n");
1292 		return -1;
1293     }
1294 
1295     playerShip = getImage(I_PLAYER1);
1296     playerTorp = getImage(I_MTORP);
1297     enemyTorp = getImage(I_ETORP);
1298     shieldImage = getImage(I_SHIELD);
1299 
1300     level=startLevel;   /* change made here */
1301 
1302     load_scores();
1303     init_titles();
1304     init_player();
1305     init_stars();
1306     init_explosions();
1307     init_score();
1308     init_prizes();
1309     init_sound();
1310     init_aliens(level);
1311     init_framerate();
1312     init_joystick();
1313 
1314     ships = 2;
1315     nextBonus = 20000;
1316 	gstate = INTRO;
1317 	plx = winwidth/2;
1318 
1319     while(1) {
1320         counter++;
1321 
1322 		S_ClearScreen();
1323 
1324 		/* For the benefit of unbuffered mode, the most important things are
1325 		 * erased/redrawn closest together so they spend the least time blanked.
1326 		 * player, aliens and etorps are most important for game play.
1327 		 * pause, title and name are important in their modes and aren't done
1328 		 * otherwise.
1329 		 *
1330 		 * The title, name, pause and score "extra ship" want to overlay
1331 		 * everything else drawn, so they come last.
1332 		 */
1333         undo_explosions();
1334         undo_prizes();
1335         undo_aliens();
1336 
1337         do_etorps();
1338         do_player(but);
1339         do_aliens();
1340         do_torps();
1341         do_prizes();
1342         do_explosions();
1343 		do_stars();
1344 
1345 		switch(gstate) {
1346 		case INTRO:
1347 			do_title();
1348 			break;
1349 
1350 		case GETTING_NAME:
1351 			do_name();
1352 			break;
1353 
1354 		case PAUSED:
1355 			do_pause();
1356 			/* fall through */
1357 
1358 		case PLAYING:
1359 			do_score();
1360 		}
1361 
1362         /* Update the display */
1363 		SDL_Flip(screen);
1364 
1365         do_framerate();
1366     }
1367     return (0);
1368 }
1369 
1370