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