1 /*
2   defendguin.c
3 
4   by Bill Kendrick
5   bill@newbreedsoftware.com
6   http://www.newbreedsoftware.com/defendguin/
7 
8   November 6, 1999 - November 5, 2009
9 */
10 
11 
12 #define VERSION "0.0.12"
13 #define SLOWDOWN 1
14 //#define SHOW_FPS
15 #define STARTING_LEVEL 1
16 
17 
18 /* Includes: */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <math.h>
25 #include <SDL.h>
26 
27 #ifndef NOSOUND
28 #include <SDL_mixer.h>
29 #endif /* #ifndef NOSOUND */
30 
31 
32 #ifndef M_PI
33 #define M_PI  3.14159265358979323846  /* mmm... pi... */
34 #endif /* #ifndef M_PI */
35 
36 
37 /* Image enumerations: */
38 
39 enum {
40   IMG_LOADING,
41   IMG_LOADING_TEXT,
42   IMG_PRESS_A_KEY,
43   IMG_TITLE_TITLE,
44   IMG_TITLE_ONE_PLAYER,
45   IMG_TITLE_TWO_PLAYERS,
46   IMG_TITLE_OPTIONS,
47   IMG_TITLE_QUIT,
48   IMG_TITLE_ARROW0,
49   IMG_TITLE_ARROW1,
50   IMG_TITLE_ARROW2,
51   IMG_TITLE_STARFIELD,
52   IMG_TUX_L0,
53   IMG_TUX_L1,
54   IMG_TUX_L2,
55   IMG_TUX_L3,
56   IMG_TUX_L4,
57   IMG_TUX_L5,
58   IMG_TUX_L6,
59   IMG_TUX_L7,
60   IMG_TUX_R0,
61   IMG_TUX_R1,
62   IMG_TUX_R2,
63   IMG_TUX_R3,
64   IMG_TUX_R4,
65   IMG_TUX_R5,
66   IMG_TUX_R6,
67   IMG_TUX_R7,
68   IMG_TUX_FALL0,
69   IMG_TUX_FALL1,
70   IMG_TUX_LFLAG,
71   IMG_TUX_RFLAG,
72   IMG_UFO0,
73   IMG_UFO1,
74   IMG_BEAM0,
75   IMG_BEAM1,
76   IMG_BEAM2,
77   IMG_BEAM3,
78   IMG_MUTANT0,
79   IMG_MUTANT1,
80   IMG_POD0,
81   IMG_POD1,
82   IMG_POD2,
83   IMG_SWARMER,
84   IMG_BOMBER,
85   IMG_BOMBER_BULGE0,
86   IMG_BOMBER_BULGE1,
87   IMG_MINE,
88   IMG_MINE_FLASH,
89   IMG_MINE_POP,
90   IMG_BAITER0,
91   IMG_BAITER1,
92   IMG_BAITER2,
93   IMG_BAITER3,
94   IMG_BAITER4,
95   IMG_EVILBILL1,
96   IMG_EVILBILL2,
97   IMG_EVILBILL_SHOOT,
98   IMG_EVILBILL_HURT1,
99   IMG_EVILBILL_HURT2,
100   IMG_EVILBILL_FLAME1,
101   IMG_EVILBILL_FLAME2,
102   IMG_EVILBILL_FLAME3,
103   IMG_BULLET0,
104   IMG_BULLET1,
105   IMG_BULLET2,
106   IMG_BULLET3,
107   IMG_BULLET4,
108   IMG_LAND_LEFT,
109   IMG_LAND_CENTER,
110   IMG_LAND_RIGHT,
111   IMG_SHIP_LEFT,
112   IMG_SHIP_RIGHT,
113   IMG_SHIP_LEFT2,
114   IMG_SHIP_RIGHT2,
115   IMG_SHIP_LEFT_DYING,
116   IMG_SHIP_RIGHT_DYING,
117   IMG_SHIP_WIN_0,
118   IMG_SHIP_WIN_1,
119   IMG_SHIP_WIN_2,
120   IMG_DISCO_1,
121   IMG_DISCO_2,
122   IMG_FLAME_LEFT_0,
123   IMG_FLAME_LEFT_1,
124   IMG_FLAME_RIGHT_0,
125   IMG_FLAME_RIGHT_1,
126   IMG_LASERS,
127   IMG_STATUS_AREA,
128   IMG_MAP_LAND,
129   IMG_MAP_PENG,
130   IMG_MAP_ALERT,
131   IMG_MAP_UFO,
132   IMG_MAP_MUTANT,
133   IMG_MAP_BOMBER,
134   IMG_MAP_MINE,
135   IMG_MAP_POD,
136   IMG_MAP_SWARMER,
137   IMG_MAP_BAITER,
138   IMG_MAP_EVILBILL,
139   IMG_MAP_SHIP,
140   IMG_SHIPS,
141   IMG_SMART_BOMB,
142   IMG_GET_READY,
143   IMG_PENGUINOID_IN_TROUBLE,
144   IMG_PENGUINOID_MUTATED,
145   IMG_CATCH_THE_PENGUINOID,
146   IMG_PENGUINOID_DROPPED,
147   IMG_PENGUINOID_SAVED,
148   IMG_PENGUINOID_SHOT,
149   IMG_PLANET_DESTROYED,
150   IMG_LEVEL_BONUS,
151   IMG_NO_BONUS,
152   IMG_GAME_OVER,
153   IMG_NUMBERS,
154   IMG_100,
155   IMG_150,
156   IMG_200,
157   IMG_250,
158   IMG_1000,
159   IMG_CIRCLE,
160   IMG_OPTION_TEXT,
161   NUM_IMAGES
162 };
163 
164 
165 /* Image filenames: */
166 
167 const char * image_names[NUM_IMAGES] = {
168   DATA_PREFIX "images/loader/loading.bmp",
169   DATA_PREFIX "images/loader/loading-text.bmp",
170   DATA_PREFIX "images/loader/press-a-key.bmp",
171   DATA_PREFIX "images/title/title.bmp",
172   DATA_PREFIX "images/title/one-player.bmp",
173   DATA_PREFIX "images/title/two-players.bmp",
174   DATA_PREFIX "images/title/options.bmp",
175   DATA_PREFIX "images/title/quit.bmp",
176   DATA_PREFIX "images/title/arrow0.bmp",
177   DATA_PREFIX "images/title/arrow1.bmp",
178   DATA_PREFIX "images/title/arrow2.bmp",
179   DATA_PREFIX "images/title/starfield.bmp",
180   DATA_PREFIX "images/tux/l0.bmp",
181   DATA_PREFIX "images/tux/l1.bmp",
182   DATA_PREFIX "images/tux/l2.bmp",
183   DATA_PREFIX "images/tux/l3.bmp",
184   DATA_PREFIX "images/tux/l4.bmp",
185   DATA_PREFIX "images/tux/l5.bmp",
186   DATA_PREFIX "images/tux/l6.bmp",
187   DATA_PREFIX "images/tux/l7.bmp",
188   DATA_PREFIX "images/tux/r0.bmp",
189   DATA_PREFIX "images/tux/r1.bmp",
190   DATA_PREFIX "images/tux/r2.bmp",
191   DATA_PREFIX "images/tux/r3.bmp",
192   DATA_PREFIX "images/tux/r4.bmp",
193   DATA_PREFIX "images/tux/r5.bmp",
194   DATA_PREFIX "images/tux/r6.bmp",
195   DATA_PREFIX "images/tux/r7.bmp",
196   DATA_PREFIX "images/tux/fall0.bmp",
197   DATA_PREFIX "images/tux/fall1.bmp",
198   DATA_PREFIX "images/tux/lflag.bmp",
199   DATA_PREFIX "images/tux/rflag.bmp",
200   DATA_PREFIX "images/ufo/ufo0.bmp",
201   DATA_PREFIX "images/ufo/ufo1.bmp",
202   DATA_PREFIX "images/ufo/beam0.bmp",
203   DATA_PREFIX "images/ufo/beam1.bmp",
204   DATA_PREFIX "images/ufo/beam2.bmp",
205   DATA_PREFIX "images/ufo/beam3.bmp",
206   DATA_PREFIX "images/mutant/mutant0.bmp",
207   DATA_PREFIX "images/mutant/mutant1.bmp",
208   DATA_PREFIX "images/pod/pod0.bmp",
209   DATA_PREFIX "images/pod/pod1.bmp",
210   DATA_PREFIX "images/pod/pod2.bmp",
211   DATA_PREFIX "images/swarmer/swarmer.bmp",
212   DATA_PREFIX "images/bomber/bomber.bmp",
213   DATA_PREFIX "images/bomber/bomber-bulge0.bmp",
214   DATA_PREFIX "images/bomber/bomber-bulge1.bmp",
215   DATA_PREFIX "images/bomber/mine.bmp",
216   DATA_PREFIX "images/bomber/mine-flash.bmp",
217   DATA_PREFIX "images/bomber/mine-pop.bmp",
218   DATA_PREFIX "images/baiter/baiter0.bmp",
219   DATA_PREFIX "images/baiter/baiter1.bmp",
220   DATA_PREFIX "images/baiter/baiter2.bmp",
221   DATA_PREFIX "images/baiter/baiter3.bmp",
222   DATA_PREFIX "images/baiter/baiter4.bmp",
223   DATA_PREFIX "images/evilbill/evilbill1.bmp",
224   DATA_PREFIX "images/evilbill/evilbill2.bmp",
225   DATA_PREFIX "images/evilbill/evilbill-shoot.bmp",
226   DATA_PREFIX "images/evilbill/evilbill-hurt1.bmp",
227   DATA_PREFIX "images/evilbill/evilbill-hurt2.bmp",
228   DATA_PREFIX "images/evilbill/flame1.bmp",
229   DATA_PREFIX "images/evilbill/flame2.bmp",
230   DATA_PREFIX "images/evilbill/flame3.bmp",
231   DATA_PREFIX "images/bullet/bullet0.bmp",
232   DATA_PREFIX "images/bullet/bullet1.bmp",
233   DATA_PREFIX "images/bullet/bullet2.bmp",
234   DATA_PREFIX "images/bullet/bullet3.bmp",
235   DATA_PREFIX "images/bullet/bullet4.bmp",
236   DATA_PREFIX "images/land/left.bmp",
237   DATA_PREFIX "images/land/center.bmp",
238   DATA_PREFIX "images/land/right.bmp",
239   DATA_PREFIX "images/ship/ship-left.bmp",
240   DATA_PREFIX "images/ship/ship-right.bmp",
241   DATA_PREFIX "images/ship/ship-left2.bmp",
242   DATA_PREFIX "images/ship/ship-right2.bmp",
243   DATA_PREFIX "images/ship/ship-left-dying.bmp",
244   DATA_PREFIX "images/ship/ship-right-dying.bmp",
245   DATA_PREFIX "images/ship/ship-win-0.bmp",
246   DATA_PREFIX "images/ship/ship-win-1.bmp",
247   DATA_PREFIX "images/ship/ship-win-2.bmp",
248   DATA_PREFIX "images/ship/disco-1.bmp",
249   DATA_PREFIX "images/ship/disco-2.bmp",
250   DATA_PREFIX "images/ship/flame-left-0.bmp",
251   DATA_PREFIX "images/ship/flame-left-1.bmp",
252   DATA_PREFIX "images/ship/flame-right-0.bmp",
253   DATA_PREFIX "images/ship/flame-right-1.bmp",
254   DATA_PREFIX "images/ship/lasers.bmp",
255   DATA_PREFIX "images/status/status-area.bmp",
256   DATA_PREFIX "images/status/map-land.bmp",
257   DATA_PREFIX "images/status/map-peng.bmp",
258   DATA_PREFIX "images/status/map-alert.bmp",
259   DATA_PREFIX "images/status/map-ufo.bmp",
260   DATA_PREFIX "images/status/map-mutant.bmp",
261   DATA_PREFIX "images/status/map-bomber.bmp",
262   DATA_PREFIX "images/status/map-mine.bmp",
263   DATA_PREFIX "images/status/map-pod.bmp",
264   DATA_PREFIX "images/status/map-swarmer.bmp",
265   DATA_PREFIX "images/status/map-baiter.bmp",
266   DATA_PREFIX "images/status/map-evilbill.bmp",
267   DATA_PREFIX "images/status/map-ship.bmp",
268   DATA_PREFIX "images/status/ships.bmp",
269   DATA_PREFIX "images/status/smart-bomb.bmp",
270   DATA_PREFIX "images/status/get-ready.bmp",
271   DATA_PREFIX "images/status/penguinoid-in-trouble.bmp",
272   DATA_PREFIX "images/status/penguinoid-mutated.bmp",
273   DATA_PREFIX "images/status/catch-the-penguinoid.bmp",
274   DATA_PREFIX "images/status/penguinoid-dropped.bmp",
275   DATA_PREFIX "images/status/penguinoid-saved.bmp",
276   DATA_PREFIX "images/status/penguinoid-shot.bmp",
277   DATA_PREFIX "images/status/planet-destroyed.bmp",
278   DATA_PREFIX "images/status/level-bonus.bmp",
279   DATA_PREFIX "images/status/no-bonus.bmp",
280   DATA_PREFIX "images/status/game-over.bmp",
281   DATA_PREFIX "images/status/numbers.bmp",
282   DATA_PREFIX "images/points/100.bmp",
283   DATA_PREFIX "images/points/150.bmp",
284   DATA_PREFIX "images/points/200.bmp",
285   DATA_PREFIX "images/points/250.bmp",
286   DATA_PREFIX "images/points/1000.bmp",
287   DATA_PREFIX "images/status/circle.bmp",
288   DATA_PREFIX "images/status/option-text.bmp"
289 };
290 
291 
292 /* Sound enumerations: */
293 
294 enum {
295   SND_SELECT,
296   SND_CONFIRM,
297   SND_IMPATIENCE,
298   SND_THRUST,
299   SND_LASER,
300   SND_SMARTBOMB,
301   SND_ONEUP,
302   SND_DIE1,
303   SND_DIE2,
304   SND_MATERIALIZE,
305   SND_PENG_CAPTURE,
306   SND_PENG_SAVE,
307   SND_PENG_DROP0,
308   SND_PENG_DROP1,
309   SND_PENG_DROP2,
310   SND_PENG_KILL,
311   SND_PENG_SPLAT,
312   SND_PENG_MUTATE,
313   SND_EXPLODE,
314   SND_SWARMERS,
315   SND_BAITER,
316   SND_BULLET,
317   SND_EVILBILL_INTRO,
318   SND_EVILBILL_SUCCESS1,
319   SND_EVILBILL_SUCCESS2,
320   SND_EVILBILL_SUCCESS3,
321   SND_EVILBILL_SHOOT,
322   SND_EVILBILL_MINE,
323   SND_EVILBILL_HURT,
324   SND_EVILBILL_LOW,
325   SND_EVILBILL_DIE,
326   SND_PLANET_DEATH,
327   SND_GAMEOVER0,
328   SND_GAMEOVER1,
329   SND_GAMEOVER2,
330   NUM_SOUNDS
331 };
332 
333 
334 /* Sound filenames: */
335 
336 const char * sound_names[NUM_SOUNDS] = {
337   DATA_PREFIX "sounds/title/select.wav",
338   DATA_PREFIX "sounds/title/confirm.wav",
339   DATA_PREFIX "sounds/title/impatience.wav",
340   DATA_PREFIX "sounds/ship/thrust.wav",
341   DATA_PREFIX "sounds/ship/laser.wav",
342   DATA_PREFIX "sounds/ship/smartbomb.wav",
343   DATA_PREFIX "sounds/ship/oneup.wav",
344   DATA_PREFIX "sounds/ship/die1.wav",
345   DATA_PREFIX "sounds/ship/die2.wav",
346   DATA_PREFIX "sounds/materialize.wav",
347   DATA_PREFIX "sounds/peng/capture.wav",
348   DATA_PREFIX "sounds/peng/save.wav",
349   DATA_PREFIX "sounds/peng/drop0.wav",
350   DATA_PREFIX "sounds/peng/drop1.wav",
351   DATA_PREFIX "sounds/peng/drop2.wav",
352   DATA_PREFIX "sounds/peng/kill.wav",
353   DATA_PREFIX "sounds/peng/splat.wav",
354   DATA_PREFIX "sounds/peng/mutate.wav",
355   DATA_PREFIX "sounds/explode.wav",
356   DATA_PREFIX "sounds/swarmers.wav",
357   DATA_PREFIX "sounds/baiter.wav",
358   DATA_PREFIX "sounds/bullet.wav",
359   DATA_PREFIX "sounds/evilbill/intro.wav",
360   DATA_PREFIX "sounds/evilbill/success1.wav",
361   DATA_PREFIX "sounds/evilbill/success2.wav",
362   DATA_PREFIX "sounds/evilbill/success3.wav",
363   DATA_PREFIX "sounds/evilbill/shoot.wav",
364   DATA_PREFIX "sounds/evilbill/mine.wav",
365   DATA_PREFIX "sounds/evilbill/hurt.wav",
366   DATA_PREFIX "sounds/evilbill/low.wav",
367   DATA_PREFIX "sounds/evilbill/die.wav",
368   DATA_PREFIX "sounds/planet_death.wav",
369   DATA_PREFIX "sounds/gameover/darn.wav",
370   DATA_PREFIX "sounds/gameover/finish.wav",
371   DATA_PREFIX "sounds/gameover/lose.wav"
372 };
373 
374 
375 #define MUS_TITLE DATA_PREFIX "music/child.mod"
376 #define MUS_LAST DATA_PREFIX "music/confusio.mod"
377 #define MUS_WIN DATA_PREFIX "music/easytrip.mod"
378 
379 #define NUM_GAME_MUSICS 5
380 
381 const char * game_music_names[NUM_GAME_MUSICS] = {
382   DATA_PREFIX "music/no!inhi1.mod",
383   DATA_PREFIX "music/wormhole.mod",
384   DATA_PREFIX "music/ants.mod",
385   DATA_PREFIX "music/summerpa.mod",
386   DATA_PREFIX "music/blowmind.mod"
387 };
388 
389 
390 #define NUM_QUOTES 9
391 
392 const char * quotes[NUM_QUOTES] = {
393   "ABOUT TO EXPLODE",
394   "ARE YOU READY",
395   "JUST PRESS THE RIGHT BUTTON",
396   "NO   LET ME FINISH",
397   "DARN  THATS THE END",
398   "I DONT LIKE TO LOSE",
399   "WRITTEN IN EMACS",
400   "I DONT PUT ANY RESTRICTIONS",
401   "ACHEM"
402 };
403 
404 
405 /* Ship directions: */
406 
407 enum {
408   DIR_LEFT,
409   DIR_RIGHT
410 };
411 
412 
413 /* Penguinoid modes: */
414 
415 enum {
416   PENG_MODE_WALKING,
417   PENG_MODE_BEAMING,
418   PENG_MODE_CAPTURED,
419   PENG_MODE_FALLING,
420   PENG_MODE_SAVED
421 };
422 
423 
424 /* Alien types: */
425 
426 enum {
427   ALIEN_UFO,
428   ALIEN_MUTANT,
429   ALIEN_BOMBER,
430   ALIEN_MINE,
431   ALIEN_POD,
432   ALIEN_SWARMER,
433   ALIEN_BAITER,
434   ALIEN_EVILBILL
435 };
436 
437 
438 /* Alien modes: */
439 
440 enum {
441   ALIEN_MODE_BEAM_IN,
442   ALIEN_MODE_NORMAL,
443   ALIEN_MODE_HOME_PENG,
444   ALIEN_MODE_BEAMING_PENG,
445   ALIEN_MODE_CAPTURED_PENG,
446   ALIEN_MODE_HOME_SHIP,
447   ALIEN_MODE_SHOOTING,
448   ALIEN_MODE_HURTING,
449   ALIEN_MODE_DYING
450 };
451 
452 
453 /* Title Options: */
454 
455 enum {
456   TITLE_OPTION_ONE_PLAYER,
457   TITLE_OPTION_TWO_PLAYERS,
458   TITLE_OPTION_OPTIONS,
459   TITLE_OPTION_QUIT,
460   NUM_TITLE_OPTIONS
461 };
462 
463 
464 /* Title option images: */
465 
466 const int title_option_images[NUM_TITLE_OPTIONS] = {
467   IMG_TITLE_ONE_PLAYER,
468   IMG_TITLE_TWO_PLAYERS,
469   IMG_TITLE_OPTIONS,
470   IMG_TITLE_QUIT
471 };
472 
473 
474 /* Arbitrary constraints: */
475 
476 #define MAX_ALIENS 32
477 #define MAX_PENGUINOIDS 16
478 #define MAX_BULLETS 64
479 #define MAX_LASERS 16
480 #define MAX_STARS 128
481 #define MAX_STARFIELDS 512
482 #define MAX_EXPLOSION_BITS 2048
483 #define MAX_POINTS 16
484 #define MAX_FLAMES 8
485 
486 #define LASER_SPEED 128
487 
488 #define LAND_WIDTH 70
489 #define LAND_HEIGHT 15
490 #define LAND_MIN_HEIGHT 10
491 
492 #define CHANCE_UFO_HOME_PENG 1000
493 #define CHANCE_UFO_SHOOT_NORMAL 150
494 #define CHANCE_UFO_SHOOT_HOME 20
495 #define CHANCE_MUTANT_SHOOT 100
496 #define CHANCE_SWARMER_SHOOT 100
497 #define CHANCE_BAITER_SHOOT 50
498 #define CHANCE_EVILBILL_SHOOT 20
499 #define CHANCE_EVILBILL_MINE 100
500 
501 
502 /* Joystick defaults: */
503 
504 /* Typedefs: */
505 
506 typedef struct alien_type {
507   int alive, type, mode, timer, shields;
508   int x, y, xm, ym, xmm, ymm;
509   int home_peng, beam_height;
510 } alien_type;
511 
512 typedef struct bullet_type {
513   int alive, timer, owner;
514   int x, y, xm, ym;
515 } bullet_type;
516 
517 typedef struct penguinoid_type {
518   int alive, mode, being_homed;
519   int x, y, xm, ym;
520 } penguinoid_type;
521 
522 typedef struct laser_type {
523   int alive;
524   int x1, x2, y;
525 } laser_type;
526 
527 typedef struct star_type {
528   int x, y;
529 } star_type;
530 
531 typedef struct starfield_type {
532   int time;
533   float radius;
534   int angle;
535 } starfield_type;
536 
537 typedef struct explosion_bit_type {
538   int alive, time, img;
539   int x, y, xm, ym;
540 } explosion_bit_type;
541 
542 typedef struct points_type {
543   int alive, time, img;
544   int x, y;
545 } points_type;
546 
547 typedef struct flame_type {
548   int alive, time, x, y, xm;
549 } flame_type;
550 
551 
552 /* Globals: */
553 
554 int x[2], y[2], xm[2], scroll[2], dir[2], lives[2], bombs[2], planet_dead[2],
555   dying[2], dancing[2], safe[2], level[2];
556 Uint32 score[2];
557 int player;
558 int dontblockchan[4];
559 float my_cos[32];
560 int highscore, num_players, vol_effects, vol_music,
561   joy_x, joy_y, joy_fire, joy_bomb;
562 int mesg_img, mesg_timer, flash, flash_colors, oneup_effect,
563   oneup_effect_counter;
564 int use_fullscreen, use_sound, use_joystick, num_joysticks;
565 SDL_Surface * screen;
566 SDL_Surface * images[NUM_IMAGES];
567 int land[2][LAND_WIDTH][LAND_HEIGHT];
568 alien_type aliens[2][MAX_ALIENS];
569 penguinoid_type penguinoids[2][MAX_PENGUINOIDS];
570 bullet_type bullets[MAX_BULLETS];
571 laser_type lasers[MAX_LASERS];
572 star_type stars[MAX_STARS];
573 explosion_bit_type explosion_bits[MAX_EXPLOSION_BITS];
574 points_type points[MAX_POINTS];
575 flame_type flames[MAX_FLAMES];
576 starfield_type starfields[MAX_STARFIELDS];
577 
578 #ifndef NOSOUND
579 Mix_Chunk * sounds[NUM_SOUNDS];
580 Mix_Music * title_music, * last_music, * win_music;
581 Mix_Music * game_musics[NUM_GAME_MUSICS];
582 #endif /* #ifndef NOSOUND */
583 
584 SDL_Joystick *js;
585 
586 
587 /* Local function prototypes: */
588 
589 int game(int mode);
590 int option_screen(void);
591 int title(void);
592 void setup(void);
593 SDL_Surface * set_vid_mode(unsigned flags);
594 void my_shutdown(void);
595 void create_land(int ply);
596 void create_penguinoids(int ply, int num);
597 void draw_number(int x, int y, int n);
598 void add_alien(int x, int y, int type, int mode, int timer);
599 void create_stars(void);
600 void add_laser(int x, int y, int dir);
601 void playsound(int snd, int chan, int blocking);
602 void add_explosion(int x, int y, int img);
603 void add_explosion_bit(int x, int y, int xm, int ym, int img);
604 void add_points(int xx, int yy, int img);
605 void add_flame(int x, int y);
606 void kill_alien(int i);
607 void add_bullet(int xx, int yy, int owner);
608 void set_message(int img);
609 void kill_player(void);
610 void add_score(int add);
611 void smartbomb(void);
612 void usage(int err);
613 void pause_screen(void);
614 void write_text(int x, int y, char * str);
615 void write_text_inv(int x, int y, char * str);
616 void write_centered_text(int y, char * str);
617 void write_num(int x, int y, int v);
618 int option_value(int opt_line);
619 void load_options(void);
620 void save_options(void);
621 
622 
623 /* --- MAIN --- */
624 
main(int argc,char * argv[])625 int main(int argc, char * argv[])
626 {
627   int mode, quit, i;
628 
629 
630   /* Check for arguments: */
631 
632   use_fullscreen = 0;
633   use_sound = 1;
634   joy_fire = 0;
635   joy_bomb = 1;
636   joy_x = 0;
637   joy_y = 1;
638   highscore = 12000;
639 
640   for (i = 0; i < 2; i++)
641     {
642       score[i] = -1;
643       level[i] = -1;
644     }
645 
646   load_options();
647 
648   for (i = 1; i < argc; i++)
649     {
650       if (strcmp(argv[i], "--fullscreen") == 0 ||
651 	  strcmp(argv[i], "-f") == 0)
652 	{
653 	  use_fullscreen = 1;
654 	}
655       else if (strcmp(argv[i], "--disable-sound") == 0 ||
656 	       strcmp(argv[i], "--nosound") == 0 ||
657 	       strcmp(argv[i], "-q") == 0)
658 	{
659 	  use_sound = 0;
660 	}
661       else if (strcmp(argv[i], "--copying") == 0 ||
662 	       strcmp(argv[i], "-c") == 0)
663 	{
664 	  printf("\nDefendguin " VERSION "\n"
665 		 "\n"
666 		 "by Bill Kendrick <bill@newbreedsoftware.com>\n"
667 		 "(c) 2002-2006 New Breed Software\n"
668 		 "\n"
669 		 "This program is free software; you can redistribute it\n"
670 		 "and/or modify it under the terms of the GNU General Public\n"
671 		 "License as published by the Free Software Foundation;\n"
672 		 "either version 2 of the License, or (at your option) any\n"
673 		 "later version.\n"
674 		 "\n"
675 		 "This program is distributed in the hope that it will be\n"
676 		 "useful and entertaining, but WITHOUT ANY WARRANTY; without\n"
677 		 "even the implied warranty of MERCHANTABILITY or FITNESS\n"
678 		 "FOR A PARTICULAR PURPOSE.  See the GNU General Public\n"
679 		 "License for more details.\n"
680 		 "\n"
681 		 "You should have received a copy of the GNU General Public\n"
682 		 "License along with this program; if not, write to the Free\n"
683 		 "Software Foundation, Inc., 59 Temple Place, Suite 330,\n"
684 		 "Boston, MA  02111-1307  USA\n"
685 		 "\n");
686 
687 	  exit(0);
688 	}
689       else if (strcmp(argv[i], "--help") == 0 ||
690 	       strcmp(argv[i], "-h") == 0)
691 	{
692 	  printf("\nDefendguin " VERSION "\n"
693 		 "\n"
694 		 "Title screen controls:\n"
695 		 "  Up/Down        Choose option\n"
696 		 "  Space/Return   Select option\n"
697 		 "  Firebutton     Select option\n"
698 		 "  Escape         Quit program\n"
699 		 "\n"
700 		 "Game controls:\n"
701 		 "  Up/Down        Move up/down\n"
702 		 "  Left/Right     Face/move left/right\n"
703 		 "  Space/FireB    Fire lasers\n"
704 		 "  Alt/FireA      Detonate Smart Bomb\n"
705 		 "  1              Thrust\n"
706 		 "  2              Reverse\n"
707 		 "\n");
708 
709 	  exit(0);
710 	}
711       else if (strcmp(argv[i], "--version") == 0 ||
712 	       strcmp(argv[i], "-v") == 0)
713 	{
714 	  printf("Defendguin " VERSION "\n");
715 	  exit(0);
716 	}
717       else if (strcmp(argv[i], "--usage") == 0 ||
718 	       strcmp(argv[i], "-u") == 0)
719 	{
720 	  usage(0);
721 	}
722       else
723 	usage(1);
724     }
725 
726 
727   /* Setup: */
728 
729   setup();
730   quit = 0;
731 
732 
733   /* MAIN INTERFACE LOOP! */
734 
735   do
736     {
737       /* Display the title screen: */
738 
739       mode = title();
740 
741 
742       /* What's our choice? */
743 
744       if (mode == TITLE_OPTION_ONE_PLAYER ||
745 	  mode == TITLE_OPTION_TWO_PLAYERS)
746 	{
747 	  /* Play the game */
748 
749 	  quit = game(mode);
750 	}
751       else if (mode == TITLE_OPTION_OPTIONS)
752 	{
753 	  /* Option screen: */
754 
755 	  quit = option_screen();
756 	}
757       else if (mode == TITLE_OPTION_QUIT)
758 	{
759 	  quit = 1;
760 	}
761     }
762   while (quit == 0);
763 
764 
765   save_options();
766 
767 
768   /* Shut down and quit: */
769 
770   my_shutdown();
771 
772   return(0);
773 }
774 
775 
776 /* Game loop: */
777 
game(int mode)778 int game(int mode)
779 {
780   SDL_Event event;
781   SDLKey key;
782   SDL_Rect dest, src;
783   int i, j, done, quit, frame, zz, tmp_x, tmp_y, img, xsize, ysize,
784     left_down, right_down, up_down, down_down, thrust_down,
785     num_players, x1, x2, num_penguinoids, num_aliens;
786   int level_beat[2], level_time[2];
787   Uint32 last_time;
788 
789 
790   /* Stop any music: */
791 
792 #ifndef NOSOUND
793   if (use_sound == 1)
794     Mix_HaltMusic();
795 #endif /* #ifndef NOSOUND */
796 
797 
798   /* Set number of players: */
799 
800   if (mode == TITLE_OPTION_ONE_PLAYER)
801     num_players = 1;
802   else
803     num_players = 2;
804 
805 
806   /* Reset keypress flags: */
807 
808   left_down = 0;
809   right_down = 0;
810   up_down = 0;
811   down_down = 0;
812   thrust_down = 0;
813 
814 
815   /* Reset player stuff: */
816 
817   for (i = 0; i < 2; i++)
818     {
819       x[i] = 0;
820       xm[i] = 0;
821       y[i] = 240;
822       safe[i] = 50;
823       scroll[i] = 128;
824       dir[i] = DIR_RIGHT;
825       lives[i] = 3;
826       bombs[i] = 3;
827       score[i] = 0;
828       level[i] = STARTING_LEVEL;
829       dying[i] = 0;
830       dancing[i] = 0;
831       planet_dead[i] = 0;
832 
833       create_land(i);
834       create_penguinoids(i, MAX_PENGUINOIDS);
835 
836       level_time[i] = 0;
837       level_beat[i] = 0;
838     }
839 
840   if (num_players == 1)
841   {
842     level[1] = -1;
843     score[1] = -1;
844   }
845 
846   /* Create stars: */
847 
848   create_stars();
849 
850 
851   /* Turn off explosion bits: */
852 
853   for (i = 0; i < MAX_EXPLOSION_BITS; i++)
854     explosion_bits[i].alive = 0;
855 
856 
857   /* Turn off points: */
858 
859   for (i = 0 ; i < MAX_POINTS; i++)
860     points[i].alive = 0;
861 
862 
863   /* Turn off flames: */
864 
865   for (i = 0 ; i < MAX_FLAMES; i++)
866     flames[i].alive = 0;
867 
868 
869   /* Create aliens: */
870 
871   for (i = 0; i < 2; i++)
872     {
873       for (j = 0; j < MAX_ALIENS; j++)
874 	aliens[i][j].alive = 0;
875     }
876 
877   for (i = 0; i < MAX_BULLETS; i++)
878     bullets[i].alive = 0;
879 
880 
881   /* Turn off lasers: */
882 
883   for (i = 0; i < MAX_LASERS; i++)
884     lasers[i].alive = 0;
885 
886 
887   /* Main game loop! */
888 
889   frame = 0;
890   key = SDLK_LAST;
891   done = 0;
892   quit = 0;
893   player = 0;
894   flash = 0;
895   flash_colors = 0;
896   oneup_effect = 0;
897   oneup_effect_counter = 0;
898 
899 
900   do
901     {
902       last_time = SDL_GetTicks();
903       frame++;
904 
905       if (level_beat[player] == 0)
906 	level_time[player]++;
907 
908 
909       while (SDL_PollEvent(&event))
910 	{
911 	  if (event.type == SDL_KEYDOWN)
912 	    {
913 	      /* A keypress! */
914 
915 	      key = event.key.keysym.sym;
916 
917 	      if (key == SDLK_ESCAPE)
918 		{
919 		  /* Escape: QUit the game and return to main menu: */
920 
921 		  done = 1;
922 		}
923 	      else if (key == SDLK_LEFT &&
924 		       dying[player] == 0 &&
925 		       dancing[player] == 0)
926 		{
927 		  right_down = 0;
928 		  left_down = 1;
929 
930 		  if (dir[player] != DIR_LEFT)
931 		    {
932 		      dir[player] = DIR_LEFT;
933 		      /* scroll[player] = scroll[player] + xm[player]; */
934 		    }
935 		}
936 	      else if (key == SDLK_RIGHT &&
937 		       dying[player] == 0 &&
938 		       dancing[player] == 0)
939 		{
940 		  left_down = 0;
941 		  right_down = 1;
942 
943 		  if (dir[player] != DIR_RIGHT)
944 		    {
945 		      dir[player] = DIR_RIGHT;
946 		    }
947 		}
948 	      else if (key == SDLK_2 && dying[player] == 0 &&
949 		       dancing[player] == 0)
950 		{
951 		  if (dir[player] == DIR_LEFT)
952 		    dir[player] = DIR_RIGHT;
953 		  else
954 		    dir[player] = DIR_LEFT;
955 
956 		  left_down = 0;
957 		  right_down = 0;
958 		}
959 	      else if (key == SDLK_1 && dying[player] == 0 &&
960 		       dancing[player] == 0)
961 		{
962 		  thrust_down = 1;
963 		}
964 	      else if (key == SDLK_UP)
965 		{
966 		  up_down = 1;
967 		}
968 	      else if (key == SDLK_DOWN)
969 		{
970 		  down_down = 1;
971 		}
972 	      else if (key == SDLK_SPACE && dying[player] == 0 &&
973 		       dancing[player] == 0)
974 		{
975 		  add_laser((xm[player] * 8) + scroll[player],
976 			    y[player] + 18 + ((rand() % 4) * 2),
977 			    dir[player]);
978 
979 		  playsound(SND_LASER, 1, 0);
980 		}
981 	      else if ((key == SDLK_RSHIFT || key == SDLK_LSHIFT ||
982 			key == SDLK_RALT || key == SDLK_LALT ||
983 			key == SDLK_RCTRL || key == SDLK_LCTRL) &&
984 		       dying[player] == 0 &&
985 		       dancing[player] == 0)
986 		{
987 		  /* Detonante smart-bomb: */
988 
989 		  smartbomb();
990 		}
991 	      else if (key == SDLK_p || key == SDLK_TAB)
992 		{
993 		  /* Pause: */
994 
995 		  pause_screen();
996 		  up_down = 0;
997 		  down_down = 0;
998 		  left_down = 0;
999 		  right_down = 0;
1000 		}
1001 	    }
1002 	  else if (event.type == SDL_KEYUP)
1003 	    {
1004 	      /* A key-release: */
1005 
1006 	      key = event.key.keysym.sym;
1007 
1008 	      if (key == SDLK_LEFT)
1009 		left_down = 0;
1010 	      else if (key == SDLK_RIGHT)
1011 		right_down = 0;
1012 	      else if (key == SDLK_UP)
1013 		up_down = 0;
1014 	      else if (key == SDLK_DOWN)
1015 		down_down = 0;
1016 	      else if (key == SDLK_1)
1017 		thrust_down = 0;
1018 	    }
1019 	  else if (event.type == SDL_JOYAXISMOTION &&
1020 		   (num_joysticks < 2 || event.jaxis.which == player))
1021 	    {
1022 	      /* Joystick event: */
1023 	      if (event.jaxis.axis == joy_x)
1024 		{
1025 		  /* Left/right motion */
1026 
1027 		  if (event.jaxis.value < -256 &&
1028 		      dying[player] == 0 &&
1029 		      dancing[player] == 0)
1030 		    {
1031 		      /* Stick left: */
1032 
1033 		      right_down = 0;
1034 		      left_down = 1;
1035 
1036 		      if (dir[player] != DIR_LEFT)
1037 			{
1038 			  dir[player] = DIR_LEFT;
1039 			}
1040 		    }
1041 		  else
1042 		    left_down = 0;
1043 
1044 
1045 		  if (event.jaxis.value > 256 &&
1046 		      dying[player] == 0 &&
1047 		      dancing[player] == 0)
1048 		    {
1049 		      /* Stick right: */
1050 
1051 		      right_down = 1;
1052 		      left_down = 0;
1053 
1054 		      if (dir[player] != DIR_RIGHT)
1055 			{
1056 			  dir[player] = DIR_RIGHT;
1057 			}
1058 		    }
1059 		  else
1060 		    right_down = 0;
1061 		}
1062 	      else if (event.jaxis.axis == joy_y)
1063 		{
1064 		  /* Up/down motion: */
1065 
1066 		  if (event.jaxis.value > 256)
1067 		    down_down = 1;
1068 		  else
1069 		    down_down = 0;
1070 
1071 		  if (event.jaxis.value < -256)
1072 		    up_down = 1;
1073 		  else
1074 		    up_down = 0;
1075 		}
1076 	    }
1077 	  else if (event.type == SDL_JOYBUTTONDOWN &&
1078 		   (num_joysticks < 2 || event.jbutton.which == player))
1079 	    {
1080 	      if (event.jbutton.button == joy_fire &&
1081 		  dying[player] == 0 &&
1082 		  dancing[player] == 0)
1083 		{
1084 		  /* Fire laser: */
1085 
1086 		  add_laser((xm[player] * 8) + scroll[player],
1087 			    y[player] + 18 + ((rand() % 4) * 2),
1088 			    dir[player]);
1089 
1090 		  playsound(SND_LASER, 1, 0);
1091 		}
1092 	      else if (event.jbutton.button == joy_bomb &&
1093 		       dying[player] == 0 &&
1094 		       dancing[player] == 0)
1095 		{
1096 		  /* Detonante smart-bomb: */
1097 
1098 		  smartbomb();
1099 		}
1100 	    }
1101 	  else if (event.type == SDL_QUIT)
1102 	    {
1103 	      quit = 1;
1104 	    }
1105 	}
1106 
1107 
1108       /* Handle beaming-in new aliens: */
1109 
1110       if (level_time[player] == 2)
1111 	{
1112 	  /* First set of aliens: */
1113 
1114 	  if (level[player] != 20)
1115 	    {
1116 	      for (i = 0; i < ((level[player] % 5) + 1) * 5; i++)
1117 		add_alien(-1, -1, ALIEN_UFO, ALIEN_MODE_BEAM_IN, 64);
1118 
1119 	      for (i = 0; i < ((level[player] - 1) * 2) && i < 8; i++)
1120 		add_alien(-1, -1, ALIEN_BOMBER, ALIEN_MODE_BEAM_IN, 64);
1121 
1122 	      for (i = 0; i < ((level[player] / 2)); i++)
1123 		add_alien(-1, -1, ALIEN_POD, ALIEN_MODE_BEAM_IN, 32);
1124 
1125 	      playsound(SND_MATERIALIZE, 3, 1);
1126 	    }
1127 	  else
1128 	    {
1129 	      /* Last level! */
1130 
1131 	      add_alien(-1, -1, ALIEN_EVILBILL, ALIEN_MODE_NORMAL, 32);
1132 	      playsound(SND_EVILBILL_INTRO, 3, 1);
1133 	    }
1134 
1135 	  set_message(IMG_GET_READY);
1136 	}
1137 
1138 
1139       if (level[player] != 20)
1140 	{
1141 	  if (level_time[player] == 1000)
1142 	    {
1143 	      /* Second set of aliens: */
1144 
1145 	      for (i = 0; i < 10; i++)
1146 		add_alien(-1, -1, ALIEN_UFO, ALIEN_MODE_BEAM_IN, 64);
1147 
1148 	      playsound(SND_MATERIALIZE, 3, 1);
1149 	    }
1150 
1151 
1152 	  if (level_time[player] >= 1500 && (level_time[player] % 500) == 0)
1153 	    {
1154 	      /* Baiters */
1155 
1156 	      add_alien(-1, -1, ALIEN_BAITER, ALIEN_MODE_BEAM_IN, 16);
1157 
1158 	      playsound(SND_BAITER, 3, 1);
1159 	    }
1160 	}
1161 
1162 
1163       /* Handle message: */
1164 
1165       if (mesg_timer > 0)
1166 	mesg_timer--;
1167 
1168 
1169       /* Handle oneup effect timer: */
1170 
1171       if (oneup_effect > 0)
1172 	{
1173 	  oneup_effect = oneup_effect - 2;
1174 
1175 	  if (oneup_effect == 0)
1176 	    {
1177 	      oneup_effect_counter--;
1178 	      if (oneup_effect_counter > 0)
1179 		oneup_effect = 32;
1180 	    }
1181 	}
1182 
1183 
1184       /* Handle ship thrust: */
1185 
1186       if ((left_down == 1 || (thrust_down == 1 &&
1187 			      dir[player] == DIR_LEFT)) &&
1188 	  dying[player] == 0 &&
1189 	  dancing[player] == 0)
1190 	{
1191 	  /* Increase our left speed: */
1192 
1193 	  if (xm[player] > -16)
1194 	    xm[player] = xm[player] - 2;
1195 
1196 	  if ((frame % 4) == 0)
1197 	    playsound(SND_THRUST, 0, 0);
1198 	}
1199       else if ((right_down == 1 || (thrust_down == 1 &&
1200 			       dir[player] == DIR_RIGHT)) &&
1201 	       dying[player] == 0 &&
1202 	       dancing[player] == 0)
1203 	{
1204 	  /* Increase our right speed: */
1205 
1206 	  if (xm[player] < 16)
1207 	    xm[player] = xm[player] + 2;
1208 
1209 	  if ((frame % 4) == 0)
1210 	    playsound(SND_THRUST, 0, 0);
1211 	}
1212       else
1213 	{
1214 	  /* Slow down if we're not pressing any keys: */
1215 
1216 	  if (xm[player] < 0)
1217 	    xm[player]++;
1218 	  else if (xm[player] > 0)
1219 	    xm[player]--;
1220 
1221 #ifndef NOSOUND
1222 	  if (use_sound == 1)
1223 	    {
1224 	      if (Mix_Playing(0))
1225 		Mix_HaltChannel(0);
1226 	    }
1227 #endif /* #ifndef NOSOUND */
1228 	}
1229 
1230 
1231       /* Move ship: */
1232 
1233       x[player] = x[player] + xm[player];
1234 
1235       if (x[player] < 0)
1236 	x[player] = x[player] + (LAND_WIDTH * 32);
1237       else if (x[player] >= (LAND_WIDTH * 32))
1238 	x[player] = x[player] - (LAND_WIDTH * 32);
1239 
1240       if (dying[player] == 0 &&
1241 	  dancing[player] == 0)
1242 	{
1243 	  if (up_down == 1 && y[player] > 80)
1244 	    y[player] = y[player] - 16;
1245 	  else if (down_down == 1 && y[player] < 448)
1246 	    y[player] = y[player] + 16;
1247 	}
1248 
1249 
1250       if (dancing[player] && y[player] < 400)
1251 	y[player]++;
1252 
1253 
1254       /* Handle ship death: */
1255 
1256       if (dying[player] > 0)
1257 	{
1258 	  dying[player]++;
1259 
1260 
1261 	  /* End of white flash?  Add some explosion bits! */
1262 
1263 	  if (dying[player] == 20)
1264 	    {
1265 	      for (i = 0; i < 64; i = i + 4)
1266 		{
1267 		  for (j = 0; j < 32; j = j + 4)
1268 		    {
1269 		      add_explosion_bit(x[player] + xm[player] + i,
1270 					y[player] + j,
1271 					(rand() % 8) - 4,
1272 					(rand() % 8) - 4,
1273 					IMG_LASERS);
1274 		    }
1275 		}
1276 	    }
1277 
1278 
1279 	  /* Come back to life: */
1280 
1281 	  if (dying[player] == 100)
1282 	    {
1283 	      lives[player]--;
1284 
1285 	      if (num_players == 2)
1286 		{
1287 		  player = 1 - player;
1288 
1289 		  if (lives[player] < 0)
1290 		    player = 1 - player;
1291 		}
1292 
1293 	      if (lives[player] >= 0)
1294 		{
1295 		  dying[player] = 0;
1296 		  x[player] = (rand() % (LAND_WIDTH * 32));
1297 		  y[player] = 240;
1298 		  xm[player] = 0;
1299 		  dir[player] = DIR_RIGHT;
1300 		  scroll[player] = 128;
1301 		  safe[player] = 50;
1302 		}
1303 	    }
1304 	}
1305 
1306 
1307       /* Handle dancing ship: */
1308 
1309       if (dancing[player] > 0)
1310 	{
1311 	  dancing[player]++;
1312 
1313 	  if (dancing[player] == 1000)
1314 	    done = 1;
1315 	}
1316 
1317 
1318       /* Handle lasers: */
1319 
1320       for (i = 0; i < MAX_LASERS; i++)
1321 	{
1322 	  if (lasers[i].alive)
1323 	    {
1324 	      /* Shoot towards the endpoint, and turn off when we hit it: */
1325 
1326 	      if (lasers[i].x2 == 640)
1327 		{
1328 		  lasers[i].x1 = lasers[i].x1 + LASER_SPEED;
1329 		  if (lasers[i].x1 >= 640)
1330 		    lasers[i].alive = 0;
1331 		}
1332 	      else if (lasers[i].x2 == 0)
1333 		{
1334 		  lasers[i].x1 = lasers[i].x1 - LASER_SPEED;
1335 		  if (lasers[i].x1 <= 0)
1336 		    lasers[i].alive = 0;
1337 		}
1338 	    }
1339 	}
1340 
1341 
1342       /* Handle bullets: */
1343 
1344       for (i = 0; i < MAX_BULLETS; i++)
1345 	{
1346 	  if (bullets[i].alive)
1347 	    {
1348 	      /* Move: */
1349 
1350 	      bullets[i].x = bullets[i].x + bullets[i].xm;
1351 	      bullets[i].y = bullets[i].y + bullets[i].ym;
1352 
1353 
1354 	      /* Wrap around: */
1355 
1356 	      if (bullets[i].x < 0)
1357 		bullets[i].x = bullets[i].x + (LAND_WIDTH * 32);
1358 	      else if (bullets[i].x > LAND_WIDTH * 32)
1359 		bullets[i].x = bullets[i].x - (LAND_WIDTH * 32);
1360 
1361 
1362 	      /* Count down: */
1363 
1364 	      bullets[i].timer--;
1365 
1366 
1367 	      /* Die? */
1368 
1369 	      if (bullets[i].y < 80 || bullets[i].y >= 480 ||
1370 		  bullets[i].timer <= 0)
1371 		bullets[i].alive = 0;
1372 
1373 
1374 	      /* Did we hit the player? */
1375 
1376 	      if (safe[player] == 0 && dying[player] == 0 &&
1377 		  dancing[player] == 0 &&
1378 		  bullets[i].x >= x[player] + (xm[player] * 8) &&
1379 		  bullets[i].x <= x[player] + (xm[player] * 8) + 64 &&
1380 		  bullets[i].y >= y[player] - 16 &&
1381 		  bullets[i].y <= y[player] + 16)
1382 		{
1383 		  /* Kill the bullet: */
1384 
1385 		  bullets[i].alive = 0;
1386 
1387 
1388 		  /* Kill the player: */
1389 
1390 		  kill_player();
1391 
1392 
1393 		  /* Evil Bill says stuff: */
1394 
1395 		  if (aliens[player][bullets[i].owner].type == ALIEN_EVILBILL)
1396 		    playsound(SND_EVILBILL_SUCCESS1 + (rand() % 3), 1, 1);
1397 		}
1398 	    }
1399 	}
1400 
1401 
1402       /* Hanlde points: */
1403 
1404       for (i = 0; i < MAX_POINTS; i++)
1405 	{
1406 	  if (points[i].alive)
1407 	    {
1408 	      /* Move up and count down: */
1409 
1410 	      points[i].y = points[i].y - 2;
1411 	      points[i].time--;
1412 
1413 
1414 	      /* If we've counted all the way down (or hit the top of
1415 		 the screen), then go away: */
1416 
1417 	      if (points[i].y <= 0 || points[i].time <= 0)
1418 		points[i].alive = 0;
1419 	    }
1420 	}
1421 
1422 
1423       /* Hanlde flames: */
1424 
1425       for (i = 0; i < MAX_FLAMES; i++)
1426 	{
1427 	  if (flames[i].alive)
1428 	    {
1429 	      /* Move up and count down: */
1430 
1431 	      flames[i].y = flames[i].y - 4;
1432 	      flames[i].x = flames[i].x + flames[i].xm;
1433 	      flames[i].time--;
1434 
1435 
1436 	      /* If we've counted all the way down (or hit the top of
1437 		 the screen), then go away: */
1438 
1439 	      if (flames[i].y <= 0 || flames[i].time <= 0)
1440 		flames[i].alive = 0;
1441 	    }
1442 	}
1443 
1444 
1445       /* Handle explosion bits: */
1446 
1447       for (i = 0; i < MAX_EXPLOSION_BITS; i++)
1448 	{
1449 	  if (explosion_bits[i].alive)
1450 	    {
1451 	      /* Move the bit: */
1452 
1453 	      explosion_bits[i].x = explosion_bits[i].x + explosion_bits[i].xm;
1454 	      explosion_bits[i].y = explosion_bits[i].y + explosion_bits[i].ym;
1455 
1456 
1457 	      /* Keep in bounds: */
1458 
1459 	      if (explosion_bits[i].x < 0)
1460 		explosion_bits[i].x = explosion_bits[i].x + (LAND_WIDTH * 32);
1461 	      else if (explosion_bits[i].x > LAND_WIDTH * 32)
1462 		explosion_bits[i].x = explosion_bits[i].x - (LAND_WIDTH * 32);
1463 
1464 	      if (explosion_bits[i].y < 80 || explosion_bits[i].y >= 480)
1465 		explosion_bits[i].alive = 0;
1466 
1467 
1468 	      /* Count time down: */
1469 
1470 	      explosion_bits[i].time--;
1471 	      if (explosion_bits[i].time <= 0)
1472 		explosion_bits[i].alive = 0;
1473 	    }
1474 	}
1475 
1476 
1477       /* Move penguinoids: */
1478 
1479       num_penguinoids = 0;
1480 
1481       for (i = 0; i < MAX_PENGUINOIDS; i++)
1482 	{
1483 	  if (penguinoids[player][i].alive)
1484 	    {
1485 	      if (level[player] != 20)
1486 		{
1487 		  if (penguinoids[player][i].mode == PENG_MODE_WALKING)
1488 		    {
1489 		      /* Move horizontally: */
1490 
1491 		      penguinoids[player][i].x =
1492 			penguinoids[player][i].x + penguinoids[player][i].xm;
1493 
1494 		      if (penguinoids[player][i].x < 0)
1495 			penguinoids[player][i].x = (penguinoids[player][i].x +
1496 					    (LAND_WIDTH * 32));
1497 		      else if (penguinoids[player][i].x > LAND_WIDTH * 32)
1498 			penguinoids[player][i].x = (penguinoids[player][i].x -
1499 					    (LAND_WIDTH * 32));
1500 
1501 
1502 		      /* Move vertically: */
1503 
1504 		      penguinoids[player][i].y =
1505 			penguinoids[player][i].y + penguinoids[player][i].ym;
1506 
1507 		      if (penguinoids[player][i].y > 448)
1508 			{
1509 			  penguinoids[player][i].y = 448;
1510 			  penguinoids[player][i].ym = -((rand() % 2) + 1);
1511 			}
1512 		      else if (land[player][penguinoids[player][i].x / 32]
1513 			       [penguinoids[player][i].y / 32]
1514 			       == -1)
1515 			{
1516 			  penguinoids[player][i].y =
1517 			    penguinoids[player][i].y + 1;
1518 
1519 			  penguinoids[player][i].ym = (rand() % 2) + 1;
1520 			}
1521 		    }
1522 		  else if (penguinoids[player][i].mode == PENG_MODE_FALLING)
1523 		    {
1524 		      /* Move vertically: */
1525 
1526 		      penguinoids[player][i].y = (penguinoids[player][i].y +
1527 						  penguinoids[player][i].ym);
1528 
1529 		      if ((frame % 2) == 0)
1530 			{
1531 			  penguinoids[player][i].ym =
1532 			    penguinoids[player][i].ym + 1;
1533 			}
1534 
1535 		      if (penguinoids[player][i].ym > 32)
1536 			penguinoids[player][i].ym = 32;
1537 
1538 
1539 		      /* Land or splat: */
1540 
1541 
1542 		      if (land[player][penguinoids[player][i].x / 32]
1543 			  [penguinoids[player][i].y / 32] != -1)
1544 			{
1545 			  if (penguinoids[player][i].ym <= 10)
1546 			    {
1547 			      /* Land: */
1548 
1549 			      penguinoids[player][i].ym = 0;
1550 			      penguinoids[player][i].mode = PENG_MODE_WALKING;
1551 			      penguinoids[player][i].being_homed = 0;
1552 			      add_score(100);
1553 			      add_points(penguinoids[player][i].x,
1554 					 penguinoids[player][i].y,
1555 					 IMG_100);
1556 			      set_message(IMG_PENGUINOID_SAVED);
1557 			    }
1558 			  else
1559 			    {
1560 			      /* Splat! */
1561 
1562 			      penguinoids[player][i].alive = 0;
1563 			      flash = 1;
1564 			      playsound(SND_PENG_SPLAT, 2, 0);
1565 			      add_explosion(penguinoids[player][i].x + 16,
1566 					    penguinoids[player][i].y + 16,
1567 					    IMG_TUX_FALL0);
1568 			      set_message(IMG_PENGUINOID_DROPPED);
1569 			    }
1570 			}
1571 
1572 
1573 		      /* Get saved by the ship!? */
1574 
1575 		      if (penguinoids[player][i].x >= (x[player] +
1576 					       (xm[player] * 8) - 32) &&
1577 			  penguinoids[player][i].x <= (x[player] +
1578 					       (xm[player] * 8) + 64) &&
1579 			  penguinoids[player][i].y >= y[player] - 32 &&
1580 			  penguinoids[player][i].y <= y[player] + 32 &&
1581 			  dying[player] == 0 &&
1582 			  dancing[player] == 0)
1583 			{
1584 			  penguinoids[player][i].mode = PENG_MODE_SAVED;
1585 			  penguinoids[player][i].being_homed = 0;
1586 			  playsound(SND_PENG_SAVE, 2, 0);
1587 			  add_score(100);
1588 			  add_points(penguinoids[player][i].x,
1589 				     penguinoids[player][i].y,
1590 				     IMG_100);
1591 			  set_message(IMG_PENGUINOID_SAVED);
1592 			}
1593 		    }
1594 		  else if (penguinoids[player][i].mode == PENG_MODE_SAVED)
1595 		    {
1596 		      /* Stick to the ship! */
1597 
1598 		      penguinoids[player][i].x = (x[player] +
1599 						  (xm[player] * 8) + 16);
1600 		      penguinoids[player][i].y = y[player] + 32;
1601 
1602 
1603 		      /* Stick to the ground if we brush against it: */
1604 
1605 		      if (land[player][penguinoids[player][i].x / 32]
1606 			  [penguinoids[player][i].y / 32] != -1)
1607 			{
1608 			  penguinoids[player][i].ym = 0;
1609 			  penguinoids[player][i].mode = PENG_MODE_WALKING;
1610 			  penguinoids[player][i].being_homed = 0;
1611 			  playsound(SND_PENG_DROP0 + (rand() % 3), 2, 1);
1612 			  add_score(250);
1613 			  add_points(penguinoids[player][i].x,
1614 				     penguinoids[player][i].y,
1615 				     IMG_250);
1616 			  set_message(IMG_PENGUINOID_SAVED);
1617 			}
1618 		    }
1619 		}
1620 	      else
1621 		{
1622 		  /* Last level!  Cheering! */
1623 
1624 		  if (num_aliens == 0)
1625 		    {
1626 		      /* No more EvilBill? Jump up and down! */
1627 
1628 		      penguinoids[player][i].y = (penguinoids[player][i].y +
1629 						  penguinoids[player][i].ym);
1630 		      penguinoids[player][i].ym++;
1631 
1632 		      if (penguinoids[player][i].ym >= 5)
1633 			{
1634 			  penguinoids[player][i].ym = 0;
1635 			  penguinoids[player][i].y =
1636 			    penguinoids[player][i].y - 10;
1637 			}
1638 
1639 
1640 		      /* Move towards ship if it's landed: */
1641 
1642 		      if (dancing[player] && y[player] == 400)
1643 			{
1644 			  if (penguinoids[player][i].x < x[player] -
1645 			      ((i + 3) * 14))
1646 			    {
1647 			      penguinoids[player][i].x =
1648 				penguinoids[player][i].x + 4;
1649 			      penguinoids[player][i].xm = 1;
1650 			    }
1651 			  else if (penguinoids[player][i].x > x[player] +
1652 				   ((i + 3) * 14))
1653 			    {
1654 			      penguinoids[player][i].x =
1655 				penguinoids[player][i].x - 4;
1656 			      penguinoids[player][i].xm = -1;
1657 			    }
1658 			}
1659 		    }
1660 		}
1661 
1662 
1663 	      /* Kill penguinoids if shot by our laser: */
1664 
1665 	      /* (determine relative position on screen (laser
1666 		 is screenbased)) */
1667 
1668 	      tmp_x = penguinoids[player][i].x - (x[player] - scroll[player]);
1669 
1670 	      if (tmp_x < -31)
1671 		tmp_x = tmp_x + (LAND_WIDTH * 32);
1672 
1673 	      while (tmp_x >= (LAND_WIDTH * 32))
1674 		tmp_x = tmp_x - (LAND_WIDTH * 32);
1675 
1676 
1677 	      /* (see if any lasers are touching the penguinoid) */
1678 
1679 	      for (j = 0; j < MAX_LASERS; j++)
1680 		{
1681 		  if (lasers[j].alive && penguinoids[player][i].alive)
1682 		    {
1683 		      if (((lasers[j].x2 == 640 &&
1684 			    tmp_x >= lasers[j].x1 && tmp_x <= 640) ||
1685 			   (lasers[j].x2 == 0 &&
1686 			    tmp_x <= lasers[j].x1 && tmp_x >= 0)) &&
1687 			  (penguinoids[player][i].y >= lasers[j].y - 32 &&
1688 			   penguinoids[player][i].y <= lasers[j].y))
1689 			{
1690 			  /* Kill the penguinoid: */
1691 
1692 			  penguinoids[player][i].alive = 0;
1693 			  flash = 1;
1694 			  playsound(SND_PENG_KILL, 2, 0);
1695 			  set_message(IMG_PENGUINOID_SHOT);
1696 
1697 			  add_explosion(penguinoids[player][i].x + 16,
1698 					penguinoids[player][i].y + 16,
1699 					IMG_TUX_FALL0);
1700 			}
1701 		    }
1702 		}
1703 
1704 	      num_penguinoids++;
1705 	    }
1706 	}
1707 
1708 
1709       /* Are there no more penguinoids? */
1710 
1711       if (num_penguinoids == 0 && planet_dead[player] == 0)
1712 	{
1713 	  /* Kill the planet! */
1714 
1715 	  playsound(SND_PLANET_DEATH, 3, 1);
1716 	  set_message(IMG_PLANET_DESTROYED);
1717 
1718 	  for (i = 0; i < LAND_WIDTH; i++)
1719 	    {
1720 	      for (j = 0; j < LAND_HEIGHT; j++)
1721 		{
1722 		  if (land[player][i][j] != -1)
1723 		    {
1724 		      add_explosion(i * 32 + 16, j * 32 + 16,
1725 				    IMG_LASERS);
1726 		      land[player][i][j] = -1;
1727 		    }
1728 		}
1729 	    }
1730 
1731 	  planet_dead[player] = 1;
1732 
1733 	  flash = 20;
1734 
1735 
1736 	  /* Turn all aliens (except mines & evilbill) into mutants: */
1737 
1738 	  for (i = 0; i < MAX_ALIENS; i++)
1739 	    {
1740 	      if (aliens[player][i].alive)
1741 		{
1742 		  if (aliens[player][i].type != ALIEN_MINE)
1743 		    {
1744 		      if (aliens[player][i].type != ALIEN_EVILBILL)
1745 			aliens[player][i].type = ALIEN_MUTANT;
1746 		    }
1747 		  else
1748 		    aliens[player][i].alive = 0;
1749 		}
1750 	    }
1751 	}
1752 
1753 
1754       /* Move aliens: */
1755 
1756       num_aliens = 0;
1757 
1758       for (i = 0; i < MAX_ALIENS; i++)
1759 	{
1760 	  if (aliens[player][i].alive)
1761 	    {
1762 	      xsize = 0;
1763 	      if (aliens[player][i].type == ALIEN_EVILBILL)
1764 		xsize = 128 - 32;
1765 
1766 	      ysize = 0;
1767 	      if (aliens[player][i].type == ALIEN_EVILBILL)
1768 		ysize = 128 - 32;
1769 
1770 	      num_aliens++;
1771 
1772 	      if (aliens[player][i].type == ALIEN_UFO)
1773 		{
1774 		  /* UFO's! */
1775 
1776 		  if (aliens[player][i].mode == ALIEN_MODE_NORMAL)
1777 		    {
1778 		      /* Move horizontally: */
1779 
1780 		      aliens[player][i].x = (aliens[player][i].x +
1781 					     aliens[player][i].xm);
1782 
1783 		      if (aliens[player][i].x < 0)
1784 			{
1785 			  aliens[player][i].x = (aliens[player][i].x +
1786 						 (LAND_WIDTH * 32));
1787 			}
1788 		      else if (aliens[player][i].x > LAND_WIDTH * 32)
1789 			{
1790 			  aliens[player][i].x = (aliens[player][i].x -
1791 						 (LAND_WIDTH * 32));
1792 			}
1793 
1794 
1795 		      /* Move vertically: */
1796 
1797 		      aliens[player][i].y = (aliens[player][i].y +
1798 					     aliens[player][i].ym);
1799 
1800 		      if (land[player][aliens[player][i].x / 32]
1801 			  [(aliens[player][i].y / 32) + 1]
1802 			  != -1)
1803 			{
1804 			  aliens[player][i].y = aliens[player][i].y - 2;
1805 			  aliens[player][i].ym = -2;
1806 			  aliens[player][i].timer = (rand() % 20) + 20;
1807 			}
1808 
1809 		      if (aliens[player][i].y < 80)
1810 			{
1811 			  aliens[player][i].y = 80;
1812 			  aliens[player][i].ym = 2;
1813 			  aliens[player][i].timer = (rand() % 20) + 20;
1814 			}
1815 
1816 		      if (aliens[player][i].y >= 448)
1817 			{
1818 			  aliens[player][i].y = 448;
1819 			  aliens[player][i].ym = 2;
1820 			}
1821 
1822 
1823 		      /* Change direction? */
1824 
1825 		      aliens[player][i].timer--;
1826 
1827 		      if (aliens[player][i].timer <= 0)
1828 			{
1829 			  aliens[player][i].ym = 2;
1830 			  aliens[player][i].timer = (rand() % 20) + 20;
1831 			}
1832 
1833 
1834 		      /* Home-in on a helpless penguinoid!? */
1835 
1836 		      if ((rand() %
1837 			   (CHANCE_UFO_HOME_PENG / (level[player] + 1))) == 0)
1838 			{
1839 			  /* Are there any close by? */
1840 
1841 			  aliens[player][i].home_peng = -1;
1842 
1843 			  for (j = 0; (j < MAX_PENGUINOIDS &&
1844 				       aliens[player][i].home_peng == -1); j++)
1845 			    {
1846 			      if (penguinoids[player][j].alive &&
1847 				  (penguinoids[player][j].x -
1848 				   aliens[player][i].x) > -200 &&
1849 				  (penguinoids[player][j].x -
1850 				   aliens[player][i].x) < 200 &&
1851 				  penguinoids[player][j].being_homed == 0)
1852 				{
1853 				  aliens[player][i].mode = ALIEN_MODE_HOME_PENG;
1854 				  aliens[player][i].home_peng = j;
1855 				  aliens[player][i].beam_height = 0;
1856 				  penguinoids[player][j].being_homed = 1;
1857 				}
1858 			    }
1859 			}
1860 		    }
1861 		  else if (aliens[player][i].mode == ALIEN_MODE_HOME_PENG ||
1862 			   aliens[player][i].mode == ALIEN_MODE_BEAMING_PENG)
1863 		    {
1864 		      /* Homing in-on, or beaming-up a penguinoid: */
1865 
1866 		      /* Move horizontally: */
1867 
1868 		      aliens[player][i].x = (aliens[player][i].x +
1869 					     aliens[player][i].xm);
1870 
1871 		      if (aliens[player][i].x < 0)
1872 			{
1873 			  aliens[player][i].x = (aliens[player][i].x +
1874 						 (LAND_WIDTH * 32));
1875 			}
1876 		      else if (aliens[player][i].x > LAND_WIDTH * 32)
1877 			{
1878 			  aliens[player][i].x = (aliens[player][i].x -
1879 						 (LAND_WIDTH * 32));
1880 			}
1881 
1882 
1883 		      /* Home-in on, and beam-up the penguinoid! */
1884 
1885 		      if (aliens[player][i].x >
1886 			  penguinoids[player]
1887 			  [aliens[player][i].home_peng].x + 2)
1888 			{
1889 			  aliens[player][i].xm = -4;
1890 			}
1891 		      else if (aliens[player][i].x <
1892 			       penguinoids[player]
1893 			       [aliens[player][i].home_peng].x - 2)
1894 			{
1895 			  aliens[player][i].xm = 4;
1896 			}
1897 		      else
1898 			{
1899 			  /* Beam-up! */
1900 
1901 			  aliens[player][i].xm = 0;
1902 			  aliens[player][i].x =
1903 			    penguinoids[player]
1904 			    [aliens[player][i].home_peng].x;
1905 
1906 			  if (aliens[player][i].y >=
1907 			      penguinoids[player]
1908 			      [aliens[player][i].home_peng].y - 34 &&
1909 			      aliens[player][i].mode !=
1910 			      ALIEN_MODE_BEAMING_PENG)
1911 			    {
1912 			      aliens[player][i].mode =
1913 				ALIEN_MODE_BEAMING_PENG;
1914 
1915 			      penguinoids[player]
1916 				[aliens[player][i].home_peng].mode =
1917 				PENG_MODE_BEAMING;
1918 
1919 			      playsound(SND_PENG_CAPTURE, 2, 1);
1920 			      set_message(IMG_PENGUINOID_IN_TROUBLE);
1921 			    }
1922 			}
1923 
1924 
1925 		      /* Move vertically: */
1926 
1927 		      aliens[player][i].y = aliens[player][i].y + 4;
1928 
1929 		      if (aliens[player][i].y >
1930 			  penguinoids[player]
1931 			  [aliens[player][i].home_peng].y - 32)
1932 			{
1933 			  aliens[player][i].y =
1934 			    penguinoids[player][aliens[player][i].home_peng].y -
1935 			    32;
1936 			}
1937 
1938 
1939 		      /* Handle the beam-up graphic: */
1940 
1941 		      if (aliens[player][i].mode == ALIEN_MODE_BEAMING_PENG &&
1942 			  (frame % 2) == 0)
1943 			{
1944 			  aliens[player][i].beam_height++;
1945 
1946 
1947 			  /* Is it captured all the way!? */
1948 
1949 			  if (aliens[player][i].beam_height == 32)
1950 			    {
1951 			      aliens[player][i].mode = ALIEN_MODE_CAPTURED_PENG;
1952 			      penguinoids[player]
1953 				[aliens[player][i].home_peng].mode =
1954 				PENG_MODE_CAPTURED;
1955 			    }
1956 			}
1957 
1958 
1959 		      /* Is the penguinoid still alive!? */
1960 
1961 		      if (penguinoids[player]
1962 			  [aliens[player][i].home_peng].alive == 0)
1963 			{
1964 			  aliens[player][i].mode = ALIEN_MODE_NORMAL;
1965 			  aliens[player][i].xm = 4;
1966 			  if ((rand() % 2) == 0)
1967 			    aliens[player][i].xm = -aliens[player][i].xm;
1968 			}
1969 		    }
1970 		  else if (aliens[player][i].mode == ALIEN_MODE_CAPTURED_PENG)
1971 		    {
1972 		      /* Captured a penguinoid!  Fly upwards! */
1973 
1974 		      aliens[player][i].y = aliens[player][i].y - 4;
1975 
1976 
1977 		      /* Turn a penguinoid and a UFO into a mutant: */
1978 
1979 		      if (aliens[player][i].y < 80)
1980 			{
1981 			  aliens[player][i].y = 80;
1982 			  aliens[player][i].type = ALIEN_MUTANT;
1983 			  aliens[player][i].mode = ALIEN_MODE_HOME_SHIP;
1984 
1985 			  penguinoids[player]
1986 			    [aliens[player][i].home_peng].alive = 0;
1987 			  playsound(SND_PENG_MUTATE, 2, 0);
1988 			  set_message(IMG_PENGUINOID_MUTATED);
1989 
1990 			  flash = 1;
1991 			}
1992 
1993 		      penguinoids[player][aliens[player][i].home_peng].y =
1994 			aliens[player][i].y + 32;
1995 
1996 
1997 		      /* Is the penguinoid still alive!? */
1998 
1999 		      if (penguinoids[player]
2000 			  [aliens[player][i].home_peng].alive == 0)
2001 			{
2002 			  aliens[player][i].mode = ALIEN_MODE_NORMAL;
2003 			  aliens[player][i].xm = 4;
2004 			  if ((rand() % 2) == 0)
2005 			    aliens[player][i].xm = -aliens[player][i].xm;
2006 			}
2007 		    }
2008 
2009 
2010 		  /* Shoot at the ship? */
2011 
2012 		  if ((aliens[player][i].mode == ALIEN_MODE_HOME_PENG &&
2013 		       (rand() %
2014 			((CHANCE_UFO_SHOOT_HOME /
2015 			  ((level[player] / 2) + 1)) + 1))
2016 		       == 0) ||
2017 		      (aliens[player][i].mode == ALIEN_MODE_NORMAL &&
2018 		       (rand() %
2019 			((CHANCE_UFO_SHOOT_NORMAL /
2020 			  ((level[player] / 2) + 1)) + 1))
2021 		       == 0))
2022 		    {
2023 		      if (abs(x[player] - aliens[player][i].x) <= 320)
2024 			{
2025 			  add_bullet(aliens[player][i].x + 4,
2026 				     aliens[player][i].y + 4, i);
2027 			}
2028 		    }
2029 		}
2030 	      else if (aliens[player][i].type == ALIEN_BOMBER)
2031 		{
2032 		  /* Move horizontally: */
2033 
2034 		  aliens[player][i].x = (aliens[player][i].x +
2035 					 aliens[player][i].xm);
2036 
2037 		  if (aliens[player][i].x < 0)
2038 		    {
2039 		      aliens[player][i].x = (aliens[player][i].x +
2040 					     (LAND_WIDTH * 32));
2041 		    }
2042 		  else if (aliens[player][i].x > LAND_WIDTH * 32)
2043 		    {
2044 		      aliens[player][i].x = (aliens[player][i].x -
2045 					     (LAND_WIDTH * 32));
2046 		    }
2047 
2048 
2049 		  /* Move vertically: */
2050 
2051 		  aliens[player][i].y = (aliens[player][i].y +
2052 					 aliens[player][i].ym);
2053 
2054 		  if (aliens[player][i].y < 80)
2055 		    aliens[player][i].y = 448;
2056 		  else if (aliens[player][i].y > 448)
2057 		    aliens[player][i].y = 80;
2058 
2059 
2060 		  /* Change direction: */
2061 
2062 		  if ((frame % 10) == 0)
2063 		    {
2064 		      aliens[player][i].ym = (aliens[player][i].ym +
2065 					      aliens[player][i].ymm);
2066 
2067 		      if (aliens[player][i].ym < -4)
2068 			aliens[player][i].ymm = 1;
2069 		      else if (aliens[player][i].ym > 4)
2070 			aliens[player][i].ymm = -1;
2071 		    }
2072 
2073 
2074 		  /* Count down timer: */
2075 
2076 		  aliens[player][i].timer--;
2077 
2078 		  if (aliens[player][i].timer < 0)
2079 		    aliens[player][i].timer = 300;
2080 
2081 
2082 		  /* Occassionally add a mine: */
2083 
2084 		  if (aliens[player][i].mode == ALIEN_MODE_NORMAL &&
2085 		      aliens[player][i].timer < 99 &&
2086 		      (aliens[player][i].timer % 33) == 0)
2087 		    {
2088 		      add_alien(aliens[player][i].x, aliens[player][i].y,
2089 				ALIEN_MINE, ALIEN_MODE_NORMAL, 200);
2090 		    }
2091 		}
2092 	      else if (aliens[player][i].type == ALIEN_POD)
2093 		{
2094 		  /* Move horizontally: */
2095 
2096 		  aliens[player][i].x = (aliens[player][i].x +
2097 					 aliens[player][i].xm);
2098 
2099 		  if (aliens[player][i].x < 0)
2100 		    {
2101 		      aliens[player][i].x = (aliens[player][i].x +
2102 					     (LAND_WIDTH * 32));
2103 		    }
2104 		  else if (aliens[player][i].x > LAND_WIDTH * 32)
2105 		    {
2106 		      aliens[player][i].x = (aliens[player][i].x -
2107 					     (LAND_WIDTH * 32));
2108 		    }
2109 
2110 		  /* Move vertically: */
2111 
2112 		  aliens[player][i].y = (aliens[player][i].y +
2113 					 aliens[player][i].ym);
2114 
2115 		  if (aliens[player][i].y < 80)
2116 		    {
2117 		      aliens[player][i].y = 80;
2118 		      aliens[player][i].ym = (rand() % 4) + 1;
2119 		    }
2120 		  else if (aliens[player][i].y > 448)
2121 		    {
2122 		      aliens[player][i].y = 448;
2123 		      aliens[player][i].ym = -((rand() % 4) + 1);
2124 		    }
2125 
2126 
2127 		  /* Count down timer: */
2128 
2129 		  aliens[player][i].timer--;
2130 
2131 
2132 		  /* Move randomly: */
2133 
2134 		  if (aliens[player][i].timer < 0)
2135 		    {
2136 		      aliens[player][i].timer = (rand() % 200) + 100;
2137 
2138 		      aliens[player][i].xm = (rand() % 4) + 1;
2139 		      if ((rand() % 2) == 0)
2140 			aliens[player][i].xm = -aliens[player][i].xm;
2141 
2142 		      aliens[player][i].ym = (rand() % 4) + 1;
2143 		      if ((rand() % 2) == 0)
2144 			aliens[player][i].ym = -aliens[player][i].ym;
2145 		    }
2146 		}
2147 	      else if (aliens[player][i].type == ALIEN_MINE)
2148 		{
2149 		  /* Count down timer: */
2150 
2151 		  aliens[player][i].timer--;
2152 
2153 
2154 		  /* Die when our time's up: */
2155 
2156 		  if (aliens[player][i].timer < 0)
2157 		    aliens[player][i].alive = 0;
2158 		}
2159 	      else if (aliens[player][i].type == ALIEN_MUTANT)
2160 		{
2161 		  if ((rand() % 10) > 3)
2162 		    {
2163 		      /* Home in on ship! */
2164 
2165 		      if (aliens[player][i].x < x[player])
2166 			{
2167 			  aliens[player][i].x = (aliens[player][i].x +
2168 						 (16 - (rand() % 8)));
2169 			}
2170 		      else if (aliens[player][i].x >= x[player])
2171 			{
2172 			  aliens[player][i].x = (aliens[player][i].x -
2173 						 (16 - (rand() % 8)));
2174 			}
2175 
2176 		      /* if (aliens[player][i].y < y[player])
2177 			 aliens[player][i].y = aliens[player][i].y +
2178 			 (4 - (rand() % 2));
2179 			 else if (aliens[player][i].y >= y[player])
2180 			 aliens[player][i].y = aliens[player][i].y -
2181 			 (4 - (rand() % 2));
2182 		      */
2183 
2184 		      aliens[player][i].y = (aliens[player][i].y +
2185 				     (my_cos[((frame + i) % 32)]) * 8);
2186 		    }
2187 		  else
2188 		    {
2189 		      /* Jitter: */
2190 
2191 		      aliens[player][i].x = (aliens[player][i].x +
2192 					     ((rand() % 16) - 8));
2193 
2194 		      aliens[player][i].y = (aliens[player][i].y +
2195 					     ((rand() % 5) - 2));
2196 		    }
2197 
2198 
2199 		  /* Spin around: */
2200 
2201 		  /* aliens[player][i].x = (aliens[player][i].x +
2202 		     my_cos[(aliens[player][i].timer % 32)] * 5);
2203 		     aliens[player][i].y = (aliens[player][i].y -
2204 		     my_cos[32 - (aliens[player][i].timer % 32)] * 5); */
2205 
2206 
2207 		  /* Keep in-bounds: */
2208 
2209 		  if (aliens[player][i].x < 0)
2210 		    {
2211 		      aliens[player][i].x = (aliens[player][i].x +
2212 					     (LAND_WIDTH * 32));
2213 		    }
2214 		  else if (aliens[player][i].x > LAND_WIDTH * 32)
2215 		    {
2216 		      aliens[player][i].x = (aliens[player][i].x -
2217 					     (LAND_WIDTH * 32));
2218 		    }
2219 
2220 		  if (aliens[player][i].y < 80)
2221 		    aliens[player][i].y = 80;
2222 		  else if (aliens[player][i].y > 448)
2223 		    aliens[player][i].y = 448;
2224 
2225 
2226 		  /* Shoot at the ship? */
2227 
2228 		  if (aliens[player][i].mode == ALIEN_MODE_NORMAL &&
2229 		      (rand() %
2230 		       ((CHANCE_MUTANT_SHOOT /
2231 			 ((level[player] / 2) + 1)) + 1)) == 0)
2232 		    {
2233 		      if (x[player] - aliens[player][i].x >= -320 &&
2234 			  x[player] - aliens[player][i].x <= 320)
2235 			{
2236 			  add_bullet(aliens[player][i].x + 12,
2237 				     aliens[player][i].y + 8, i);
2238 			}
2239 		    }
2240 		}
2241 	      else if (aliens[player][i].type == ALIEN_SWARMER)
2242 		{
2243 		  /* Home in on ship! */
2244 
2245 		  if ((frame % 10) != 0 &&
2246 		      aliens[player][i].x >= x[player] - 600 &&
2247 		      aliens[player][i].x <= x[player] + 600)
2248 		    {
2249 		      if (aliens[player][i].x < x[player])
2250 			aliens[player][i].x = aliens[player][i].x + 8;
2251 		      else if (aliens[player][i].x > x[player])
2252 			aliens[player][i].x = aliens[player][i].x - 8;
2253 
2254 		      if (aliens[player][i].y < y[player])
2255 			{
2256 			  aliens[player][i].ym = aliens[player][i].ym + 1;
2257 			  if (aliens[player][i].ym > 4)
2258 			    aliens[player][i].ym = 4;
2259 			}
2260 		      else if (aliens[player][i].y > y[player])
2261 			{
2262 			  aliens[player][i].ym = aliens[player][i].ym - 1;
2263 			  if (aliens[player][i].ym < -4)
2264 			    aliens[player][i].ym = -4;
2265 			}
2266 		    }
2267 		  else
2268 		    {
2269 		      aliens[player][i].x = (aliens[player][i].x +
2270 					     aliens[player][i].xm);
2271 
2272 		      aliens[player][i].timer--;
2273 		      if (aliens[player][i].timer <= 0)
2274 			{
2275 			  aliens[player][i].timer = (rand() % 50) + 50;
2276 
2277 			  aliens[player][i].xm = (rand() % 6) + 1;
2278 			  if ((rand() % 2) == 0)
2279 			    aliens[player][i].xm = -aliens[player][i].xm;
2280 
2281 			  aliens[player][i].ym = (rand() % 6) + 1;
2282 			  if ((rand() % 2) == 0)
2283 			    aliens[player][i].ym = -aliens[player][i].ym;
2284 			}
2285 		    }
2286 
2287 		  aliens[player][i].y = (aliens[player][i].y +
2288 					 aliens[player][i].ym);
2289 
2290 
2291 		  /* Keep in-bounds: */
2292 
2293 		  if (aliens[player][i].x < 0)
2294 		    {
2295 		      aliens[player][i].x = (aliens[player][i].x +
2296 					     (LAND_WIDTH * 32));
2297 		    }
2298 		  else if (aliens[player][i].x > LAND_WIDTH * 32)
2299 		    {
2300 		      aliens[player][i].x = (aliens[player][i].x -
2301 					     (LAND_WIDTH * 32));
2302 		    }
2303 
2304 		  if (aliens[player][i].y < 80)
2305 		    aliens[player][i].y = 80;
2306 		  else if (aliens[player][i].y > 448)
2307 		    aliens[player][i].y = 448;
2308 
2309 
2310 		  /* Shoot at the ship? */
2311 
2312 		  if ((rand() %
2313 		       ((CHANCE_SWARMER_SHOOT /
2314 			 ((level[player] / 2) + 1)) + 1))
2315 		      == 0)
2316 		    {
2317 		      if (x[player] - aliens[player][i].x >= -320 &&
2318 			  x[player] - aliens[player][i].x <= 320)
2319 			{
2320 			  add_bullet(aliens[player][i].x,
2321 				     aliens[player][i].y, i);
2322 			}
2323 		    }
2324 		}
2325 	      else if (aliens[player][i].type == ALIEN_BAITER)
2326 		{
2327 		  /* Move alien: */
2328 
2329 		  aliens[player][i].x = (aliens[player][i].x +
2330 					 aliens[player][i].xm);
2331 
2332 		  aliens[player][i].y = (aliens[player][i].y +
2333 					 aliens[player][i].ym);
2334 
2335 
2336 		  /* Keep in-bounds: */
2337 
2338 		  if (aliens[player][i].x < 0)
2339 		    {
2340 		      aliens[player][i].x = (aliens[player][i].x +
2341 					     (LAND_WIDTH * 32));
2342 		    }
2343 		  else if (aliens[player][i].x > LAND_WIDTH * 32)
2344 		    {
2345 		      aliens[player][i].x = (aliens[player][i].x -
2346 					     (LAND_WIDTH * 32));
2347 		    }
2348 
2349 		  if (aliens[player][i].y < 80)
2350 		    {
2351 		      aliens[player][i].y = 80;
2352 		      aliens[player][i].ym = 0;
2353 		    }
2354 		  else if (aliens[player][i].y > 448)
2355 		    {
2356 		      aliens[player][i].y = 448;
2357 		      aliens[player][i].ym = 0;
2358 		    }
2359 
2360 
2361 		  /* Home-in on player: */
2362 
2363 		  if (aliens[player][i].x > x[player])
2364 		    {
2365 		      aliens[player][i].xm--;
2366 		      if (aliens[player][i].xm < -16)
2367 			aliens[player][i].xm = -16;
2368 		    }
2369 		  else if (aliens[player][i].x < x[player])
2370 		    {
2371 		      aliens[player][i].xm++;
2372 		      if (aliens[player][i].xm > 16)
2373 			aliens[player][i].xm = 16;
2374 		    }
2375 
2376 		  if (aliens[player][i].y > y[player])
2377 		    {
2378 		      aliens[player][i].ym--;
2379 		      if (aliens[player][i].ym < -8)
2380 			aliens[player][i].ym = -8;
2381 		    }
2382 		  else if (aliens[player][i].y < y[player])
2383 		    {
2384 		      aliens[player][i].ym++;
2385 		      if (aliens[player][i].ym > 32)
2386 			aliens[player][i].ym = 32;
2387 		    }
2388 
2389 
2390 		  /* Shoot at the ship? */
2391 
2392 		  if ((rand() %
2393 		       ((CHANCE_BAITER_SHOOT /
2394 			 ((level[player] / 2) + 1)) + 1)) == 0)
2395 		    {
2396 		      if (x[player] - aliens[player][i].x >= -320 &&
2397 			  x[player] - aliens[player][i].x <= 320)
2398 			{
2399 			  add_bullet(aliens[player][i].x,
2400 				     aliens[player][i].y, i);
2401 			}
2402 		    }
2403 		}
2404 	      else if (aliens[player][i].type == ALIEN_EVILBILL)
2405 		{
2406 		  /* Move alien: */
2407 
2408 		  if (aliens[player][i].mode == ALIEN_MODE_NORMAL ||
2409 		      (aliens[player][i].mode == ALIEN_MODE_HURTING &&
2410 		       aliens[player][i].timer < 5))
2411 		    {
2412 		      aliens[player][i].x = (aliens[player][i].x +
2413 					     aliens[player][i].xm);
2414 
2415 		      aliens[player][i].y = (aliens[player][i].y +
2416 					     aliens[player][i].ym);
2417 
2418 
2419 		      /* Keep in-bounds: */
2420 
2421 		      if (aliens[player][i].x < 0)
2422 			{
2423 			  aliens[player][i].x = (aliens[player][i].x +
2424 						 (LAND_WIDTH * 32));
2425 			}
2426 		      else if (aliens[player][i].x > LAND_WIDTH * 32)
2427 			{
2428 			  aliens[player][i].x = (aliens[player][i].x -
2429 						 (LAND_WIDTH * 32));
2430 			}
2431 
2432 		      if (aliens[player][i].y < 80)
2433 			{
2434 			  aliens[player][i].y = 80;
2435 			  aliens[player][i].ym = 0;
2436 			}
2437 		      else if (aliens[player][i].y > 448)
2438 			{
2439 			  aliens[player][i].y = 448;
2440 			  aliens[player][i].ym = 0;
2441 			}
2442 
2443 
2444 		      /* Home-in on player: */
2445 
2446 		      if (aliens[player][i].x > x[player])
2447 			{
2448 			  aliens[player][i].xm--;
2449 			  if (aliens[player][i].xm < -16)
2450 			    aliens[player][i].xm = -16;
2451 			}
2452 		      else if (aliens[player][i].x < x[player])
2453 			{
2454 			  aliens[player][i].xm++;
2455 			  if (aliens[player][i].xm > 16)
2456 			    aliens[player][i].xm = 16;
2457 			}
2458 
2459 		      if (aliens[player][i].y > y[player])
2460 			{
2461 			  aliens[player][i].ym--;
2462 			  if (aliens[player][i].ym < -8)
2463 			    aliens[player][i].ym = -8;
2464 			}
2465 		      else if (aliens[player][i].y < y[player])
2466 			{
2467 			  aliens[player][i].ym++;
2468 			  if (aliens[player][i].ym > 32)
2469 			    aliens[player][i].ym = 32;
2470 			}
2471 		    }
2472 		  else if (aliens[player][i].mode == ALIEN_MODE_DYING)
2473 		    {
2474 		      /* Crash to the ground: */
2475 
2476 		      aliens[player][i].y = (aliens[player][i].y +
2477 					     aliens[player][i].ym);
2478 
2479 		      if (frame % 4)
2480 			aliens[player][i].ym++;
2481 
2482 		      if (aliens[player][i].y >= 480)
2483 			{
2484 			  kill_alien(i);
2485 			  flash = 50;
2486 			  flash_colors = 1;
2487 			}
2488 
2489 
2490 		      /* Spray out bits: */
2491 
2492 		      add_explosion(aliens[player][i].x + (rand() % 128),
2493 				    aliens[player][i].y + (rand() % 128),
2494 				    IMG_LASERS);
2495 		    }
2496 
2497 
2498 		  /* Shoot at the ship? */
2499 
2500 		  if ((aliens[player][i].mode == ALIEN_MODE_NORMAL ||
2501 		       (aliens[player][i].mode == ALIEN_MODE_HURTING &&
2502 			aliens[player][i].timer < 2)) &&
2503 		      (rand() % CHANCE_EVILBILL_SHOOT) == 0)
2504 		    {
2505 		      if (x[player] - aliens[player][i].x >= -320 &&
2506 			  x[player] - aliens[player][i].x <= 320)
2507 			{
2508 			  add_bullet(aliens[player][i].x + 64,
2509 				     aliens[player][i].y + 64, i);
2510 			  aliens[player][i].mode = ALIEN_MODE_SHOOTING;
2511 			  aliens[player][i].timer = 5;
2512 			  playsound(SND_EVILBILL_SHOOT, 1, 0);
2513 			}
2514 		    }
2515 
2516 
2517 		  /* Drop a mine!? */
2518 
2519 		  if (aliens[player][i].mode == ALIEN_MODE_NORMAL &&
2520 		      (rand() % CHANCE_EVILBILL_MINE) == 0)
2521 		    {
2522 		      add_alien(aliens[player][i].x + 48,
2523 				aliens[player][i].y + 48, ALIEN_MINE,
2524 				ALIEN_MODE_NORMAL, 200);
2525 		      playsound(SND_EVILBILL_MINE, 1, 0);
2526 		    }
2527 
2528 
2529 		  /* Make flames if hurt a lot: */
2530 
2531 		  if (aliens[player][i].shields < 8 && (rand() % 5) == 0)
2532 		    {
2533 		      add_flame(aliens[player][i].x + (rand() % 160) - 16,
2534 				aliens[player][i].y + (rand() % 160) - 16);
2535 		    }
2536 
2537 
2538 		  /* Count down timer: */
2539 
2540 		  if (aliens[player][i].timer > 0)
2541 		    {
2542 		      aliens[player][i].timer--;
2543 
2544 		      if (aliens[player][i].timer == 0 &&
2545 			  aliens[player][i].mode != ALIEN_MODE_DYING)
2546 			{
2547 			  aliens[player][i].mode = ALIEN_MODE_NORMAL;
2548 			}
2549 		    }
2550 		}
2551 
2552 
2553 	      /* Handle beaming-in of all aliens: */
2554 
2555 	      if (aliens[player][i].mode == ALIEN_MODE_BEAM_IN)
2556 		{
2557 		  aliens[player][i].timer--;
2558 
2559 		  if (aliens[player][i].timer <= 0)
2560 		    {
2561 		      aliens[player][i].mode = ALIEN_MODE_NORMAL;
2562 		      aliens[player][i].timer = (rand() % 20) + 20;
2563 		    }
2564 		}
2565 
2566 
2567 	      if (aliens[player][i].type != ALIEN_MINE)
2568 		{
2569 		  /* Kill aliens if shot by our laser: */
2570 
2571 		  /* (determine relative position on screen (laser
2572 		     is screenbased)) */
2573 
2574 		  tmp_x = aliens[player][i].x - (x[player] - scroll[player]);
2575 
2576 		  if (tmp_x < -31)
2577 		    tmp_x = tmp_x + (LAND_WIDTH * 32);
2578 
2579 		  while (tmp_x >= (LAND_WIDTH * 32))
2580 		    tmp_x = tmp_x - (LAND_WIDTH * 32);
2581 
2582 
2583 		  /* (see if any lasers are touching the alien) */
2584 
2585 		  for (j = 0; j < MAX_LASERS; j++)
2586 		    {
2587 		      if (lasers[j].alive && aliens[player][i].alive)
2588 			{
2589 			  if (((lasers[j].x2 == 640 &&
2590 				tmp_x >= lasers[j].x1 && tmp_x <= 640) ||
2591 			       (lasers[j].x2 == 0 &&
2592 				tmp_x <= lasers[j].x1 - 32 && tmp_x >= 0)) &&
2593 			      (aliens[player][i].y + ysize >=
2594 			       lasers[j].y - 32 &&
2595 			       aliens[player][i].y <= lasers[j].y) &&
2596 			      aliens[player][i].mode != ALIEN_MODE_HURTING &&
2597 			      aliens[player][i].mode != ALIEN_MODE_DYING)
2598 			    {
2599 			      /* Kill the alien: */
2600 
2601 			      kill_alien(i);
2602 
2603 
2604 			      /* If it was a pod, make a bunch of swarmers: */
2605 
2606 			      if (aliens[player][i].type == ALIEN_POD)
2607 				{
2608 				  add_alien(aliens[player][i].x - 32,
2609 					    aliens[player][i].y - 64,
2610 					    ALIEN_SWARMER,
2611 					    ALIEN_MODE_NORMAL, 1);
2612 
2613 				  add_alien(aliens[player][i].x + 32,
2614 					    aliens[player][i].y - 64,
2615 					    ALIEN_SWARMER,
2616 					    ALIEN_MODE_NORMAL, 1);
2617 
2618 				  add_alien(aliens[player][i].x - 32,
2619 					    aliens[player][i].y + 64,
2620 					    ALIEN_SWARMER,
2621 					    ALIEN_MODE_NORMAL, 1);
2622 
2623 				  add_alien(aliens[player][i].x + 32,
2624 					    aliens[player][i].y + 64,
2625 					    ALIEN_SWARMER,
2626 					    ALIEN_MODE_NORMAL, 1);
2627 
2628 				  playsound(SND_SWARMERS, 1, 0);
2629 				}
2630 			    }
2631 			}
2632 		    }
2633 		}
2634 
2635 
2636 	      /* See if we've collided with the player! */
2637 
2638 	      if (safe[player] == 0 && dying[player] == 0 &&
2639 		  dancing[player] == 0 &&
2640 		  aliens[player][i].x + xsize >= (x[player] +
2641 						  (xm[player] * 8) - 16) &&
2642 		  aliens[player][i].x <= x[player] + (xm[player] * 8) + 80 &&
2643 		  aliens[player][i].y + ysize >= y[player] - 16 &&
2644 		  aliens[player][i].y <= y[player] + 16 &&
2645 		  aliens[player][i].mode != ALIEN_MODE_BEAM_IN &&
2646 		  aliens[player][i].mode != ALIEN_MODE_HURTING &&
2647 		  aliens[player][i].mode != ALIEN_MODE_DYING)
2648 		{
2649 		  /* Kill the alien: */
2650 
2651 		  kill_alien(i);
2652 
2653 
2654 		  /* Kill the player: */
2655 
2656 		  kill_player();
2657 		}
2658 	    }
2659 	}
2660 
2661 
2662       /* Beam more aliens in if they're all dead early... */
2663 
2664       if (num_aliens == 0 &&
2665 	  level_time[player] > 100 && level_time[player] < 1000)
2666 	{
2667 	  level_time[player] = 999;
2668 	}
2669 
2670 
2671       /* Advance to the next level? */
2672 
2673       if (num_aliens == 0 && level_time[player] > 1000 &&
2674 	  level_beat[player] == 0 && level[player] != 20)
2675 	{
2676 	  level_beat[player] = 1;
2677 	  level[player]++;
2678 
2679 
2680 	  /* Regenerate the planet every 5th level: */
2681 
2682 	  if (planet_dead[player] == 1 && (level[player] % 5) == 0)
2683 	    {
2684 	      planet_dead[player] = 0;
2685 	      create_land(player);
2686 	      create_penguinoids(player, MAX_PENGUINOIDS);
2687 	    }
2688 
2689 
2690 	  /* Get ready for last level music: */
2691 
2692 	  if (level[player] == 20)
2693 	    {
2694 #ifndef NOSOUND
2695 	      if (use_sound == 1)
2696 		{
2697 		  Mix_HaltMusic();
2698 		}
2699 #endif /* #ifndef NOSOUND */
2700 	    }
2701 	}
2702 
2703 
2704       /* Has the level been beat? */
2705 
2706       if (level_beat[player] > 0)
2707 	{
2708 	  level_beat[player]++;
2709 
2710 
2711 	  if (level_beat[player] >= 170 - MAX_PENGUINOIDS &&
2712 	      (level_beat[player] - (170 - MAX_PENGUINOIDS)) < num_penguinoids)
2713 	    {
2714 	      /* Explode bonus penguins: */
2715 
2716 	      add_points((((640 - (num_penguinoids * 32)) / 2) +
2717 			  ((level_beat[player] -
2718 			    (170 - MAX_PENGUINOIDS)) * 32) + 16 +
2719 			  x[player] - scroll[player]),
2720 			 80 + (images[IMG_LEVEL_BONUS] -> h) + 32,
2721 			 IMG_100);
2722 	      add_score(100);
2723 	    }
2724 
2725 
2726 	  if (level_beat[player] >= 170)
2727 	    {
2728 	      /* Reset clocks: */
2729 
2730 	      level_time[player] = 0;
2731 	      level_beat[player] = 0;
2732 	    }
2733 	}
2734 
2735 
2736       /* Handle safe mode: */
2737 
2738       if (safe[player] > 0)
2739 	safe[player]--;
2740 
2741 
2742       /* Handle scrolling position: */
2743 
2744       if (scroll[player] > 128 && dir[player] == DIR_RIGHT)
2745 	scroll[player] = scroll[player] - 16;
2746       else if (scroll[player] < 448 && dir[player] == DIR_LEFT)
2747 	scroll[player] = scroll[player] + 16;
2748 
2749 
2750       /* Draw screen: */
2751 
2752       /* (Erase to background): */
2753 
2754       dest.x = 0;
2755       dest.y = 0;
2756       dest.w = 640;
2757       dest.h = 480;
2758 
2759       if (flash == 0 || (frame % 2) == 0)
2760 	SDL_FillRect(screen, &dest,
2761 		     SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
2762       else
2763 	{
2764 	  if (flash_colors == 0)
2765 	    {
2766 	      SDL_FillRect(screen, &dest,
2767 			   SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
2768 	    }
2769 	  else
2770 	    {
2771 	      SDL_FillRect(screen, &dest,
2772 			   SDL_MapRGB(screen->format,
2773 				      (Uint8) (rand() % 256),
2774 				      (Uint8) (rand() % 256),
2775 				      (Uint8) (rand() % 256)));
2776 	    }
2777 	  flash--;
2778 
2779 	  if (flash <= 0)
2780 	    flash_colors = 0;
2781 	}
2782 
2783 
2784       /* (status area): */
2785 
2786       dest.x = 0;
2787       dest.y = 0;
2788       dest.w = 640;
2789       dest.h = 80;
2790 
2791       SDL_BlitSurface(images[IMG_STATUS_AREA], NULL, screen, &dest);
2792 
2793 
2794       /* (radar details): */
2795 
2796       /* ((ground)): */
2797 
2798       for (i = 0; i < LAND_WIDTH; i++)
2799 	{
2800 	  for (j = 0; j < LAND_HEIGHT; j++)
2801 	    {
2802 	      if (land[player][i][j] != -1)
2803 		{
2804 		  dest.x = ((i * 32) - (x[player] - scroll[player])
2805 			    + 3040);
2806 
2807 		  if (dest.x < 0)
2808 		    dest.x = dest.x + (LAND_WIDTH * 32);
2809 
2810 		  while (dest.x >= (LAND_WIDTH * 32))
2811 		    dest.x = dest.x - (LAND_WIDTH * 32);
2812 
2813 		  dest.x = (dest.x / 8) + 177;
2814 		  dest.y = (j * 4) + 6;
2815 		  dest.w = 4;
2816 		  dest.h = 4;
2817 
2818 		  if (land[player][i][j] == IMG_LAND_LEFT)
2819 		    src.x = 0;
2820 		  else if (land[player][i][j] == IMG_LAND_CENTER)
2821 		    src.x = 4;
2822 		  else if (land[player][i][j] == IMG_LAND_RIGHT)
2823 		    src.x = 8;
2824 
2825 		  src.y = 0;
2826 		  src.w = 4;
2827 		  src.h = 4;
2828 
2829 		  SDL_BlitSurface(images[IMG_MAP_LAND], &src, screen, &dest);
2830 		}
2831 	    }
2832 	}
2833 
2834 
2835       /* ((penguinoids)): */
2836 
2837       for (i = 0; i < MAX_PENGUINOIDS; i++)
2838 	{
2839 	  if (penguinoids[player][i].alive)
2840 	    {
2841 	      dest.x = (penguinoids[player][i].x - (x[player] - scroll[player])
2842 			+ 3040);
2843 
2844 	      if (dest.x < 0)
2845 		dest.x = dest.x + (LAND_WIDTH * 32);
2846 
2847 	      while (dest.x >= (LAND_WIDTH * 32))
2848 		dest.x = dest.x - (LAND_WIDTH * 32);
2849 
2850 	      dest.x = (dest.x / 8) + 177;
2851 	      dest.y = (penguinoids[player][i].y / 8) + 6;
2852 	      dest.w = 4;
2853 	      dest.h = 4;
2854 
2855 	      SDL_BlitSurface(images[IMG_MAP_PENG], NULL, screen, &dest);
2856 
2857 
2858 	      /* Draw an alert if he's captured! */
2859 
2860 	      if ((penguinoids[player][i].mode == PENG_MODE_BEAMING ||
2861 		   penguinoids[player][i].mode == PENG_MODE_CAPTURED) &&
2862 		  (frame % 2) == 0)
2863 		{
2864 		  dest.x = dest.x - 2;
2865 		  dest.y = dest.y - 2;
2866 		  dest.w = 8;
2867 		  dest.h = 8;
2868 
2869 		  SDL_BlitSurface(images[IMG_MAP_ALERT], NULL, screen, &dest);
2870 		}
2871 	    }
2872 	}
2873 
2874 
2875       /* ((aliens)): */
2876 
2877       for (i = 0; i < MAX_ALIENS; i++)
2878 	{
2879 	  if (aliens[player][i].alive &&
2880 	      (aliens[player][i].mode != ALIEN_MODE_BEAM_IN ||
2881 	       (frame % 2) == 0))
2882 	    {
2883 	      /* Determine it's position on the radar: */
2884 
2885 	      dest.x = (aliens[player][i].x - (x[player] - scroll[player])
2886 			+ 3040);
2887 
2888 	      if (dest.x < 0)
2889 		dest.x = dest.x + (LAND_WIDTH * 32);
2890 
2891 	      while (dest.x >= (LAND_WIDTH * 32))
2892 		dest.x = dest.x - (LAND_WIDTH * 32);
2893 
2894 	      dest.x = (dest.x / 8) + 177;
2895 	      dest.y = (aliens[player][i].y / 8) + 6;
2896 	      dest.w = 4;
2897 	      dest.h = 4;
2898 
2899 
2900 	      /* Which picture to use: */
2901 
2902 	      if (aliens[player][i].type == ALIEN_UFO)
2903 		img = IMG_MAP_UFO;
2904 	      else if (aliens[player][i].type == ALIEN_BOMBER)
2905 		img = IMG_MAP_BOMBER;
2906 	      else if (aliens[player][i].type == ALIEN_MINE)
2907 		img = IMG_MAP_MINE;
2908 	      else if (aliens[player][i].type == ALIEN_POD)
2909 		img = IMG_MAP_POD;
2910 	      else if (aliens[player][i].type == ALIEN_SWARMER)
2911 		img = IMG_MAP_SWARMER;
2912 	      else if (aliens[player][i].type == ALIEN_MUTANT)
2913 		img = IMG_MAP_MUTANT;
2914 	      else if (aliens[player][i].type == ALIEN_BAITER)
2915 		img = IMG_MAP_BAITER;
2916 	      else if (aliens[player][i].type == ALIEN_EVILBILL)
2917 		img = IMG_MAP_EVILBILL;
2918 
2919 
2920 	      /* Draw it! */
2921 
2922 	      SDL_BlitSurface(images[img], NULL, screen, &dest);
2923 	    }
2924 	}
2925 
2926 
2927       /* ((ship)): */
2928 
2929       dest.x = ((xm[player] * 8 + scroll[player]) / 8) + 280;
2930       dest.y = (y[player] / 8) + 6;
2931       dest.w = 6;
2932       dest.h = 4;
2933 
2934       SDL_BlitSurface(images[IMG_MAP_SHIP], NULL, screen, &dest);
2935 
2936 
2937       /* (each player's status): */
2938 
2939       for (i = 0; i < num_players; i++)
2940 	{
2941 	  /* ((number of ships)): */
2942 
2943 	  for (j = 0; j < lives[i] && j < 11; j++)
2944 	    {
2945 	      if (lives[i] < 7)
2946 		dest.x = j * 24 + (470 * i);
2947 	      else
2948 		dest.x = j * 12 + (470 * i);
2949 
2950 	      dest.y = 24;
2951 	      dest.w = 24;
2952 	      dest.h = 16;
2953 
2954 	      SDL_BlitSurface(images[IMG_SHIPS], NULL, screen, &dest);
2955 	    }
2956 
2957 
2958 	  /* ((number of bombs)): */
2959 
2960 	  for (j = 0; j < bombs[i] && j < 9; j++)
2961 	    {
2962 	      if (i == 0)
2963 		dest.x = 144;
2964 	      else
2965 		dest.x = 616;
2966 
2967 	      if (bombs[i] < 6)
2968 		dest.y = 60 - (j * 13);
2969 	      else
2970 		dest.y = 60 - (j * 7);
2971 
2972 	      dest.w = 24;
2973 	      dest.h = 13;
2974 
2975 	      SDL_BlitSurface(images[IMG_SMART_BOMB], NULL, screen, &dest);
2976 	    }
2977 
2978 
2979 	  /* ((score)): */
2980 
2981 	  if (player != i || (frame % 10) < 5)
2982 	    draw_number(470 * i, 40, score[i]);
2983 
2984 
2985 	  /* ((level)): */
2986 	  draw_number(470 * i, 0, level[i]);
2987 	}
2988 
2989 
2990       /* (stars): */
2991 
2992       for (i = 0; i < MAX_STARS; i++)
2993 	{
2994 	  /* Width of stars depends on speed of ship: */
2995 
2996 	  j = abs(xm[player] / 2);
2997 	  if (j == 0)
2998 	    j = 1;
2999 
3000 
3001 	  /* Horizontal position of star? */
3002 
3003 	  dest.x = stars[i].x - (x[player] - scroll[player]) / 2 - j;
3004 
3005 	  if (dest.x < -31)
3006 	    dest.x = dest.x + (LAND_WIDTH * 16);
3007 
3008 	  while (dest.x >= (LAND_WIDTH * 16))
3009 	    dest.x = dest.x - (LAND_WIDTH * 16);
3010 
3011 	  if (dest.x > -31 && dest.x < 640)
3012 	    {
3013 	      dest.y = stars[i].y;
3014 	      dest.w = j;
3015 	      dest.h = 1;
3016 
3017 	      src.x = 0;
3018 	      src.y = (rand() % 32);
3019 	      src.w = j;
3020 	      src.h = 1;
3021 
3022 	      SDL_BlitSurface(images[IMG_LASERS], &src, screen, &dest);
3023 	    }
3024 	}
3025 
3026 
3027       /* (ground): */
3028 
3029       for (j = 0; j < LAND_HEIGHT; j++)
3030 	{
3031 	  for (i = -1; i < 21; i++)
3032 	    {
3033 	      zz = i + ((x[player] - scroll[player]) / 32);
3034 	      if (zz < 0)
3035 		zz = zz + LAND_WIDTH;
3036 	      else if (zz >= LAND_WIDTH)
3037 		zz = zz - LAND_WIDTH;
3038 
3039 	      if (land[player][zz][j] != -1)
3040 		{
3041 		  dest.x = (i * 32) - ((x[player] - scroll[player]) % 32);
3042 
3043 		  if (dest.x > -31 && dest.x < 640)
3044 		    {
3045 		      dest.y = j * 32;
3046 		      dest.w = 32;
3047 		      dest.h = 32;
3048 
3049 		      SDL_BlitSurface(images[land[player][zz][j]],
3050 				      NULL, screen, &dest);
3051 		    }
3052 		}
3053 	    }
3054 	}
3055 
3056 
3057       /* (explosion bits): */
3058 
3059       for (i = 0; i < MAX_EXPLOSION_BITS; i++)
3060 	{
3061 	  if (explosion_bits[i].alive)
3062 	    {
3063 	      dest.x = explosion_bits[i].x - (x[player] - scroll[player]);
3064 
3065 	      if (dest.x < -31)
3066 		dest.x = dest.x + (LAND_WIDTH * 16);
3067 
3068 	      while (dest.x >= (LAND_WIDTH * 16))
3069 		dest.x = dest.x - (LAND_WIDTH * 16);
3070 
3071 	      if (dest.x > -31 && dest.x < 640)
3072 		{
3073 		  dest.y = explosion_bits[i].y;
3074 		  dest.w = 4;
3075 		  dest.h = 4;
3076 
3077 		  src.x = (rand() % 27);
3078 		  src.y = (rand() % 27);
3079 		  src.w = 4;
3080 		  src.h = 4;
3081 
3082 		  SDL_BlitSurface(images[explosion_bits[i].img],
3083 				  &src, screen, &dest);
3084 		}
3085 	    }
3086 	}
3087 
3088 
3089       /* (penguinoids): */
3090 
3091       for (i = 0; i < MAX_PENGUINOIDS; i++)
3092 	{
3093 	  if (penguinoids[player][i].alive)
3094 	    {
3095 	      dest.x = penguinoids[player][i].x - (x[player] - scroll[player]);
3096 
3097 	      if (dest.x < -31)
3098 		dest.x = dest.x + (LAND_WIDTH * 32);
3099 
3100 	      while (dest.x >= (LAND_WIDTH * 32))
3101 		dest.x = dest.x - (LAND_WIDTH * 32);
3102 
3103 	      if (dest.x > -31 && dest.x < 640)
3104 		{
3105 		  dest.y = penguinoids[player][i].y;
3106 		  dest.w = 32;
3107 		  dest.h = 32;
3108 
3109 
3110 		  if (level[player] != 20)
3111 		    {
3112 		      if (penguinoids[player][i].mode == PENG_MODE_SAVED)
3113 			{
3114 			  if (dir[player] == DIR_LEFT)
3115 			    j = IMG_TUX_L0;
3116 			  else
3117 			    j = IMG_TUX_R0;
3118 			}
3119 		      else if (penguinoids[player][i].mode ==
3120 			       PENG_MODE_FALLING ||
3121 			       penguinoids[player][i].mode ==
3122 			       PENG_MODE_CAPTURED)
3123 			{
3124 			  j = IMG_TUX_FALL0 + ((frame / 4) % 2);
3125 			}
3126 		      else
3127 			{
3128 			  if (penguinoids[player][i].xm < 0)
3129 			    j = IMG_TUX_L0;
3130 			  else
3131 			    j = IMG_TUX_R0;
3132 
3133 			  j = j + (((frame + i) / 4) % 8);
3134 			}
3135 		    }
3136 		  else
3137 		    {
3138 		      /* Final level!: */
3139 
3140 		      if (penguinoids[player][i].xm < 0)
3141 			j = IMG_TUX_LFLAG;
3142 		      else
3143 			j = IMG_TUX_RFLAG;
3144 		    }
3145 
3146 		  SDL_BlitSurface(images[j], NULL, screen, &dest);
3147 		}
3148 	    }
3149 	}
3150 
3151 
3152       /* (aliens): */
3153 
3154       for (i = 0; i < MAX_ALIENS; i++)
3155 	{
3156 	  if (aliens[player][i].alive)
3157 	    {
3158 	      /* Determine it's horizontal position: */
3159 
3160 	      tmp_x = aliens[player][i].x - (x[player] - scroll[player]);
3161 
3162 	      if (tmp_x < -31)
3163 		tmp_x = tmp_x + (LAND_WIDTH * 32);
3164 
3165 	      while (tmp_x >= (LAND_WIDTH * 32))
3166 		tmp_x = tmp_x - (LAND_WIDTH * 32);
3167 
3168 
3169 	      if (tmp_x > -31 && tmp_x < 640)
3170 		{
3171 		  /* Which picture? */
3172 
3173 		  if (aliens[player][i].type == ALIEN_UFO)
3174 		    img = IMG_UFO0 + ((frame + i) % 2);
3175 		  else if (aliens[player][i].type == ALIEN_MUTANT)
3176 		    img = IMG_MUTANT0 + ((frame / 4) % 2);
3177 		  else if (aliens[player][i].type == ALIEN_BOMBER)
3178 		    {
3179 		      img = IMG_BOMBER;
3180 
3181 
3182 		      /* (Is the bomber bulging?) */
3183 
3184 		      if (aliens[player][i].mode == ALIEN_MODE_NORMAL &&
3185 			  aliens[player][i].timer < 100)
3186 			{
3187 			  if ((aliens[player][i].timer % 33) < 5)
3188 			    img = IMG_BOMBER_BULGE1;
3189 			  else if ((aliens[player][i].timer % 33) < 10)
3190 			    img = IMG_BOMBER_BULGE0;
3191 			}
3192 		    }
3193 		  else if (aliens[player][i].type == ALIEN_MINE)
3194 		    {
3195 		      if (aliens[player][i].timer > 3)
3196 			{
3197 			  if ((frame % 4) < 2 &&
3198 			      abs(aliens[player][i].x - x[player]) < 100 &&
3199 			      abs(aliens[player][i].y - y[player]) < 100)
3200 			    img = IMG_MINE_FLASH;
3201 			  else
3202 			    img = IMG_MINE;
3203 			}
3204 		      else
3205 			img = IMG_MINE_POP;
3206 		    }
3207 		  else if (aliens[player][i].type == ALIEN_POD)
3208 		    {
3209 		      img = IMG_POD0 + ((frame / 4) % 3);
3210 		    }
3211 		  else if (aliens[player][i].type == ALIEN_SWARMER)
3212 		    {
3213 		      img = IMG_SWARMER;
3214 		    }
3215 		  else if (aliens[player][i].type == ALIEN_BAITER)
3216 		    {
3217 		      img = IMG_BAITER0 + (frame % 5);
3218 		    }
3219 		  else if (aliens[player][i].type == ALIEN_EVILBILL)
3220 		    {
3221 		      if (aliens[player][i].mode == ALIEN_MODE_SHOOTING)
3222 			img = IMG_EVILBILL_SHOOT;
3223 		      else if (aliens[player][i].mode == ALIEN_MODE_HURTING ||
3224 			       aliens[player][i].mode == ALIEN_MODE_DYING)
3225 			img = IMG_EVILBILL_HURT1 + (frame % 2);
3226 		      else
3227 			img = IMG_EVILBILL1 + ((frame / 4) % 2);
3228 		    }
3229 
3230 
3231 		  /* Draw the damned thing already! */
3232 
3233 		  if (aliens[player][i].mode != ALIEN_MODE_BEAM_IN)
3234 		    {
3235 		      /* Not beaming in, just draw it: */
3236 
3237 		      dest.x = tmp_x;
3238 		      dest.y = aliens[player][i].y;
3239 		      dest.w = images[img] -> w;
3240 		      dest.h = images[img] -> h;
3241 
3242 		      SDL_BlitSurface(images[img], NULL, screen, &dest);
3243 
3244 
3245 		      /* Beaming-up a penguinoid!? */
3246 
3247 		      if (aliens[player][i].mode == ALIEN_MODE_BEAMING_PENG)
3248 			{
3249 			  dest.x = tmp_x;
3250 			  dest.y = aliens[player][i].y + 32;
3251 			  dest.w = 32;
3252 			  dest.h = aliens[player][i].beam_height;
3253 
3254 			  src.x = 0;
3255 			  src.y = 0;
3256 			  src.w = 32;
3257 			  src.h = aliens[player][i].beam_height;
3258 
3259 			  SDL_BlitSurface(images[IMG_BEAM0 + (frame % 4)],
3260 					  &src, screen, &dest);
3261 			}
3262 		    }
3263 		  else
3264 		    {
3265 		      /* Beaming in - draw it beaming in! */
3266 
3267 		      for (j = (frame % 2); j < 32; j = j + 2)
3268 			{
3269 			  dest.x = (tmp_x +
3270 				    (my_cos[(j + aliens[player][i].timer) % 32]
3271 				     * (aliens[player][i].timer / 2)));
3272 			  dest.y = aliens[player][i].y + j;
3273 			  dest.w = 32;
3274 			  dest.h = 1;
3275 
3276 			  src.x = 0;
3277 			  src.y = j;
3278 			  src.w = 32;
3279 			  src.h = 1;
3280 
3281 			  SDL_BlitSurface(images[img], &src, screen, &dest);
3282 			}
3283 		    }
3284 		}
3285 	    }
3286 	}
3287 
3288 
3289       /* (ship): */
3290 
3291       dest.x = (xm[player] * 8) + scroll[player];
3292       dest.y = y[player];
3293       dest.w = 64;
3294       dest.h = 32;
3295 
3296       if (dancing[player] == 0)
3297 	{
3298 	  if (dying[player] == 0)
3299 	    {
3300 	      /* Ship: */
3301 
3302 	      if (safe[player] == 0 || (frame % 2) == 0)
3303 		{
3304 		  SDL_BlitSurface(images[IMG_SHIP_LEFT + (player * 2) +
3305 					dir[player]],
3306 				  NULL, screen, &dest);
3307 		}
3308 	    }
3309 	  else if (dying[player] < 20)
3310 	    {
3311 	      /* Exploding ship: */
3312 
3313 	      SDL_BlitSurface(images[IMG_SHIP_LEFT + dir[player] + 4],
3314 			      NULL, screen, &dest);
3315 	    }
3316 	}
3317       else
3318 	{
3319 	  /* Dancing Torvalds! */
3320 
3321 	  dest.h = 64;
3322 
3323 	  if (dancing[player] < 20)
3324 	    {
3325 	      /* Door is open... */
3326 
3327 	      SDL_BlitSurface(images[IMG_SHIP_WIN_0],
3328 			      NULL, screen, &dest);
3329 	    }
3330 	  else
3331 	    {
3332 	      /* ... and there's Linus! */
3333 
3334 	      SDL_BlitSurface(images[IMG_SHIP_WIN_1 + ((frame / 10) % 2)],
3335 			      NULL, screen, &dest);
3336 
3337 
3338 	      if (dancing[player] > 200)
3339 		{
3340 		  /* Disco ball: */
3341 
3342 		  dest.x = 304;
3343 		  dest.y = 80;
3344 		  dest.w = 32;
3345 		  dest.h = dancing[player] - 200;
3346 
3347 		  if (dest.h > (images[IMG_DISCO_1] -> h))
3348 		    dest.h = (images[IMG_DISCO_1] -> h);
3349 
3350 		  src.x = 0;
3351 		  src.y = images[IMG_DISCO_1] -> h - dest.h;
3352 		  src.w = 32;
3353 		  src.h = dest.h;
3354 
3355 		  SDL_BlitSurface(images[IMG_DISCO_1 + ((frame / 5) % 2)],
3356 				  &src, screen, &dest);
3357 		}
3358 	    }
3359 	}
3360 
3361 
3362       /* (oneup effect) */
3363 
3364       if (oneup_effect > 0)
3365 	{
3366 	  for (tmp_y = 0; tmp_y < 32; tmp_y = tmp_y + 4)
3367 	    {
3368 	      for (tmp_x = 0; tmp_x < 64; tmp_x = tmp_x + 4)
3369 		{
3370 		  dest.x = (xm[player] * 8) + scroll[player] +
3371 		    ((tmp_x - 32) * oneup_effect) + 32;
3372 		  dest.y = y[player] +
3373 		    ((tmp_y - 16) * oneup_effect) + 16;
3374 		  dest.w = 4;
3375 		  dest.h = 4;
3376 
3377 		  src.x = tmp_x;
3378 		  src.y = tmp_y;
3379 		  src.w = 4;
3380 		  src.h = 4;
3381 
3382 		  SDL_BlitSurface(images[IMG_SHIP_LEFT + (player * 2) +
3383 					dir[player]],
3384 				  &src, screen, &dest);
3385 		}
3386 	    }
3387 	}
3388 
3389 
3390       /* (bullets): */
3391 
3392       for (i = 0; i < MAX_BULLETS; i++)
3393 	{
3394 	  if (bullets[i].alive)
3395 	    {
3396 	      tmp_x = bullets[i].x - (x[player] - scroll[player]);
3397 
3398 	      if (tmp_x < -31)
3399 		tmp_x = tmp_x + (LAND_WIDTH * 32);
3400 
3401 	      while (tmp_x >= (LAND_WIDTH * 32))
3402 		tmp_x = tmp_x - (LAND_WIDTH * 32);
3403 
3404 	      if (tmp_x > -31 && tmp_x < 640)
3405 		{
3406 		  dest.x = tmp_x;
3407 		  dest.y = bullets[i].y;
3408 		  dest.w = 8;
3409 		  dest.h = 8;
3410 
3411 		  SDL_BlitSurface(images[IMG_BULLET0 + ((i + frame) % 5)],
3412 				  NULL, screen, &dest);
3413 		}
3414 	    }
3415 	}
3416 
3417 
3418       /* (lasers): */
3419 
3420       for (i = 0; i < MAX_LASERS; i++)
3421 	{
3422 	  if (lasers[i].alive)
3423 	    {
3424 	      src.x = 0;
3425 	      src.y = (rand() % 32);
3426 	      src.w = 8;
3427 	      src.h = 1;
3428 
3429 	      if (lasers[i].x1 < lasers[i].x2)
3430 		{
3431 		  x1 = lasers[i].x1;
3432 		  x2 = lasers[i].x2;
3433 		}
3434 	      else
3435 		{
3436 		  x1 = lasers[i].x2;
3437 		  x2 = lasers[i].x1;
3438 		}
3439 
3440 	      for (tmp_x = x1; tmp_x < x2; tmp_x = tmp_x + 8)
3441 		{
3442 		  dest.x = tmp_x;
3443 		  dest.y = lasers[i].y;
3444 		  dest.w = 8;
3445 		  dest.h = 1;
3446 
3447 		  SDL_BlitSurface(images[IMG_LASERS], &src, screen, &dest);
3448 		}
3449 	    }
3450 	}
3451 
3452 
3453       /* (engine flames): */
3454 
3455       if ((right_down == 1 || thrust_down == 1) && dir[player] == DIR_RIGHT)
3456 	{
3457 	  dest.x = (xm[player] * 8) + scroll[player] - 32;
3458 	  dest.y = y[player];
3459 	  dest.w = 32;
3460 	  dest.h = 32;
3461 
3462 	  SDL_BlitSurface(images[IMG_FLAME_RIGHT_0 + (frame % 2)],
3463 			  NULL, screen, &dest);
3464 	}
3465 
3466       if ((left_down == 1 || thrust_down == 1) && dir[player] == DIR_LEFT)
3467 	{
3468 	  dest.x = (xm[player] * 8) + scroll[player] + 64;
3469 	  dest.y = y[player];
3470 	  dest.w = 32;
3471 	  dest.h = 32;
3472 
3473 	  SDL_BlitSurface(images[IMG_FLAME_LEFT_0 + (frame % 2)],
3474 			  NULL, screen, &dest);
3475 	}
3476 
3477 
3478       /* (evilbill-hurt flames): */
3479 
3480       for (i = 0; i < MAX_FLAMES; i++)
3481 	{
3482 	  if (flames[i].alive)
3483 	    {
3484 	      tmp_x = flames[i].x - (x[player] - scroll[player]);
3485 
3486 	      if (tmp_x < -31)
3487 		tmp_x = tmp_x + (LAND_WIDTH * 32);
3488 
3489 	      while (tmp_x >= (LAND_WIDTH * 32))
3490 		tmp_x = tmp_x - (LAND_WIDTH * 32);
3491 
3492 	      if (tmp_x > -31 && tmp_x < 640)
3493 		{
3494 		  dest.x = tmp_x;
3495 		  dest.y = flames[i].y;
3496 		  dest.w = 32;
3497 		  dest.h = 32;
3498 
3499 		  SDL_BlitSurface(images[IMG_EVILBILL_FLAME3 -
3500 					flames[i].time / 4],
3501 				  NULL, screen, &dest);
3502 		}
3503 	    }
3504 	}
3505 
3506 
3507       /* (points): */
3508 
3509       for (i = 0; i < MAX_POINTS; i++)
3510 	{
3511 	  if (points[i].alive)
3512 	    {
3513 	      dest.x = points[i].x;
3514 	      dest.y = points[i].y;
3515 	      dest.w = 32;
3516 	      dest.h = 16;
3517 
3518 	      SDL_BlitSurface(images[points[i].img], NULL, screen, &dest);
3519 	    }
3520 	}
3521 
3522 
3523       /* (message): */
3524 
3525       if (mesg_timer > 0)
3526 	{
3527 	  dest.x = (640 - (images[mesg_img] -> w)) / 2;
3528 	  dest.y = 80;
3529 	  dest.w = (images[mesg_img] -> w);
3530 	  dest.h = (images[mesg_img] -> h);
3531 
3532 	  SDL_BlitSurface(images[mesg_img], NULL, screen, &dest);
3533 	}
3534 
3535 
3536       /* (level bonus): */
3537 
3538       if (level_beat[player] > 0)
3539 	{
3540 	  /* "Level Bonus" text: */
3541 
3542 	  dest.x = (640 - (images[IMG_LEVEL_BONUS] -> w)) / 2;
3543 	  dest.y = 80;
3544 	  dest.w = images[IMG_LEVEL_BONUS] -> w;
3545 
3546 	  src.x = 0;
3547 	  src.y = 0;
3548 	  src.w = images[IMG_LEVEL_BONUS] -> w;
3549 
3550 	  if (level_beat[player] < (images[IMG_LEVEL_BONUS] -> h))
3551 	    {
3552 	      dest.h = level_beat[player];
3553 	      src.h = level_beat[player];
3554 	    }
3555 	  else
3556 	    {
3557 	      dest.h = images[IMG_LEVEL_BONUS] -> h;
3558 	      src.h = images[IMG_LEVEL_BONUS] -> h;
3559 	    }
3560 
3561 	  SDL_BlitSurface(images[IMG_LEVEL_BONUS], &src, screen, &dest);
3562 
3563 
3564 	  /* Extra penguins: */
3565 
3566 	  for (i = 0; i < num_penguinoids && i < (level_beat[player] / 5); i++)
3567 	    {
3568 	      if (level_beat[player] < 170 - MAX_PENGUINOIDS ||
3569 		  (level_beat[player] - (170 - MAX_PENGUINOIDS)) < i)
3570 		{
3571 		  dest.x = ((640 - (num_penguinoids * 32)) / 2) + (i * 32);
3572 		  dest.y = 80 + (images[IMG_LEVEL_BONUS] -> h) + 16;
3573 		  dest.w = 32;
3574 		  dest.h = 32;
3575 
3576 		  SDL_BlitSurface(images[IMG_TUX_L0], NULL, screen, &dest);
3577 		}
3578 	    }
3579 
3580 
3581 	  /* "No Bonus" */
3582 
3583 	  if (num_penguinoids == 0 &&
3584 	      level_beat[player] > (images[IMG_LEVEL_BONUS] -> h) / 2)
3585 	    {
3586 	      dest.x = (640 - (images[IMG_NO_BONUS] -> w)) / 2;
3587 	      dest.y = 80 + (images[IMG_LEVEL_BONUS] -> h) + 16;
3588 	      dest.w = images[IMG_NO_BONUS] -> w;
3589 	      dest.h = images[IMG_NO_BONUS] -> h;
3590 
3591 	      SDL_BlitSurface(images[IMG_NO_BONUS], NULL, screen, &dest);
3592 	    }
3593 	}
3594 
3595 
3596       /* (game over): */
3597 
3598       if (lives[player] < 0)
3599 	{
3600 	  /* "Game Over" text: */
3601 
3602 	  for (i = 0; i < (images[IMG_GAME_OVER] -> h); i++)
3603 	    {
3604 	      dest.x = (((640 - (images[IMG_GAME_OVER] -> w)) / 2) +
3605 			(my_cos[(i + frame) % 32] * 2));
3606 	      dest.y = ((480 - (images[IMG_GAME_OVER] -> h)) / 2) + i;
3607 	      dest.w = images[IMG_GAME_OVER] -> w;
3608 	      dest.h = 1;
3609 
3610 	      src.x = 0;
3611 	      src.y = i;
3612 	      src.w = images[IMG_GAME_OVER] -> w;
3613 	      src.h = 1;
3614 
3615 	      SDL_BlitSurface(images[IMG_GAME_OVER], &src, screen, &dest);
3616 	    }
3617 
3618 
3619 	  /* Extra penguins: */
3620 
3621 	  for (i = 0; i < num_penguinoids && i < (level_beat[player] / 5); i++)
3622 	    {
3623 	      if (level_beat[player] < 170 - MAX_PENGUINOIDS ||
3624 		  (level_beat[player] - (170 - MAX_PENGUINOIDS)) < i)
3625 		{
3626 		  dest.x = ((640 - (num_penguinoids * 32)) / 2) + (i * 32);
3627 		  dest.y = 80 + (images[IMG_LEVEL_BONUS] -> h) + 16;
3628 		  dest.w = 32;
3629 		  dest.h = 32;
3630 
3631 		  SDL_BlitSurface(images[IMG_TUX_L0], NULL, screen, &dest);
3632 		}
3633 	    }
3634 
3635 
3636 	  /* "No Bonus" */
3637 
3638 	  if (num_penguinoids == 0 &&
3639 	      level_beat[player] > (images[IMG_LEVEL_BONUS] -> h) / 2)
3640 	    {
3641 	      dest.x = (640 - (images[IMG_NO_BONUS] -> w)) / 2;
3642 	      dest.y = 80 + (images[IMG_LEVEL_BONUS] -> h) + 16;
3643 	      dest.w = images[IMG_NO_BONUS] -> w;
3644 	      dest.h = images[IMG_NO_BONUS] -> h;
3645 
3646 	      SDL_BlitSurface(images[IMG_NO_BONUS], NULL, screen, &dest);
3647 	    }
3648 	}
3649 
3650 
3651       /* FLIP SCREEN! */
3652 
3653 #ifdef SHOW_FPS
3654       draw_number(0, 240, last_time + (33 * SLOWDOWN) - SDL_GetTicks());
3655 #endif /* #ifdef SHOW_FPS */
3656 
3657       SDL_Flip(screen);
3658 
3659 
3660       /* Pause: */
3661 
3662       if (SDL_GetTicks() < last_time + (33 * SLOWDOWN))
3663 	{
3664 	  SDL_Delay(last_time + (33 * SLOWDOWN) - SDL_GetTicks());
3665 	}
3666 
3667 
3668       /* Keep playing music: */
3669 
3670 #ifndef NOSOUND
3671       if (use_sound == 1)
3672         {
3673           if (!Mix_PlayingMusic())
3674 	    {
3675 	      if (level[player] != 20)
3676 		Mix_PlayMusic(game_musics[rand() % NUM_GAME_MUSICS], 0);
3677 	      else
3678 		{
3679 		  if (num_aliens > 0)
3680 		    Mix_PlayMusic(last_music, 0);
3681 		  else
3682 		    Mix_PlayMusic(win_music, 0);
3683 		}
3684 
3685 	      Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
3686 	    }
3687         }
3688 #endif /* #ifndef NOSOUND */
3689     }
3690   while (done == 0 && quit == 0);
3691 
3692 
3693   /* Stop music and play game-over sound: */
3694 
3695 #ifndef NOSOUND
3696   if (use_sound == 1 && dancing[player] == 0)
3697     {
3698       Mix_HaltMusic();
3699       Mix_HaltChannel(-1);
3700       playsound(SND_GAMEOVER0 + (rand() % 3), 0, 1);
3701 
3702       do
3703 	{
3704 	  SDL_Delay(100);
3705 	}
3706       while (Mix_Playing(0));
3707     }
3708 #endif /* #ifndef NOSOUND */
3709 
3710 
3711   return(quit);
3712 }
3713 
3714 
3715 /* Option screen loop: */
3716 
option_screen(void)3717 int option_screen(void)
3718 {
3719   SDL_Event event;
3720   SDL_Rect dest;
3721   SDLKey key;
3722   Uint32 last_time;
3723   int done, quit, option_line, old_option_line, frame;
3724 
3725   option_line = 3;
3726   done = 0;
3727   quit = 0;
3728 
3729   /* SDL_FillRect(screen, NULL,
3730      SDL_MapRGB(screen->format, 0x00, 0x00, 0x00)); */
3731 
3732   dest.x = 100;
3733   dest.y = 96;
3734   dest.w = 440;
3735   dest.h = 280;
3736 
3737   SDL_FillRect(screen, &dest,
3738 	       SDL_MapRGB(screen->format, 0x80, 0x80, 0x80));
3739 
3740   dest.x = 102;
3741   dest.y = 110;
3742   dest.w = 436;
3743   dest.h = 264;
3744 
3745   SDL_FillRect(screen, &dest,
3746 	       SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
3747 
3748   write_text(14, 10, "o --defendmacs---------------------------------- =ox");
3749 
3750   SDL_Flip(screen);
3751 
3752   write_text(14, 12, "# Defendguin Options File   Automatically Generated");
3753 
3754   write_text(14, 14, "CONFIG_EFFECTS_VOLUME =");
3755   write_num(38, 14, vol_effects);
3756 
3757   write_text(14, 15, "CONFIG_MUSIC_VOLUME =");
3758   write_num(38, 15, vol_music);
3759 
3760   write_text(14, 16, "CONFIG_JOY_FIRE =");
3761   write_num(38, 16, joy_fire);
3762 
3763   write_text(14, 17, "CONFIG_JOY_BOMB =");
3764   write_num(38, 17, joy_bomb);
3765 
3766   write_text(14, 18, "CONFIG_JOY_X_AXIS =");
3767   write_num(38, 18, joy_x);
3768 
3769   write_text(14, 19, "CONFIG_JOY_Y_AXIS =");
3770   write_num(38, 19, joy_y);
3771 
3772 
3773   write_text_inv(14, 23,
3774 		 "--#--  defendguinrc  Ovwrt --L7--All----------------");
3775 
3776   write_text(14, 24, "Key translations");
3777   write_text(14, 26, "key          binding");
3778   write_text(14, 27, "---          -------");
3779   write_text(14, 28, "up           prev-option");
3780   write_text(14, 29, "down         next-option");
3781   write_text(14, 30, "left         decrease-option-value");
3782   write_text(14, 31, "right        increase-option-value");
3783   write_text(14, 33, "ESC          save-some-options");
3784 
3785   write_text_inv(14, 35,
3786 		 "-1---  #Help#    Help View--L1--All-----------------");
3787 
3788   frame = 0;
3789 
3790   do
3791     {
3792       last_time = SDL_GetTicks();
3793       frame++;
3794 
3795 
3796       /* Check for keypresses: */
3797 
3798       old_option_line = option_line;
3799 
3800       while (SDL_PollEvent(&event))
3801 	{
3802 	  if (event.type == SDL_KEYDOWN)
3803 	    {
3804 	      key = event.key.keysym.sym;
3805 
3806 	      if (key == SDLK_ESCAPE)
3807 		{
3808 		  done = 1;
3809 		}
3810 	      else if (key == SDLK_UP)
3811 		{
3812 		  if (option_line > 3)
3813 		    option_line--;
3814 		}
3815 	      else if (key == SDLK_DOWN)
3816 		{
3817 		  if (option_line < 8)
3818 		    option_line++;
3819 		}
3820 	      else if (key == SDLK_LEFT)
3821 	        {
3822 		  if (option_line == 3)
3823 		  {
3824 		    if (vol_effects > 0)
3825 		    {
3826 		      vol_effects--;
3827 		      Mix_Volume(-1, vol_effects * (MIX_MAX_VOLUME / 5));
3828 	              playsound(SND_SELECT, -1, 0);
3829 		    }
3830 		  }
3831 		  else if (option_line == 4)
3832 		  {
3833 		    if (vol_music > 0)
3834 		    {
3835 		      vol_music--;
3836 		      Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
3837 		    }
3838 		  }
3839 		  else if (option_line == 5)
3840 		  {
3841 		    if (joy_fire > 0)
3842 		      joy_fire--;
3843 		  }
3844 		  else if (option_line == 6)
3845 		  {
3846 		    if (joy_bomb > 0)
3847 		      joy_bomb--;
3848 		  }
3849 		  else if (option_line == 7)
3850 		  {
3851 		    if (joy_x > 0)
3852 		      joy_x--;
3853 		  }
3854 		  else if (option_line == 8)
3855 		  {
3856 		    if (joy_y > 0)
3857 		      joy_y--;
3858 		  }
3859 	        }
3860 	      else if (key == SDLK_RIGHT)
3861 	        {
3862 		  if (option_line == 3)
3863 		  {
3864 		    if (vol_effects < 5)
3865 		    {
3866 		      vol_effects++;
3867 		      Mix_Volume(-1, vol_effects * (MIX_MAX_VOLUME / 5));
3868 	              playsound(SND_SELECT, -1, 0);
3869 		    }
3870 		  }
3871 		  else if (option_line == 4)
3872 		  {
3873 		    if (vol_music < 5)
3874 		    {
3875 		      vol_music++;
3876 		      Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
3877 		    }
3878 		  }
3879 		  else if (option_line == 5)
3880 		  {
3881 		    if (joy_fire < 12)
3882 		      joy_fire++;
3883 		  }
3884 		  else if (option_line == 6)
3885 		  {
3886 		    if (joy_bomb < 12)
3887 		      joy_bomb++;
3888 		  }
3889 		  else if (option_line == 7)
3890 		  {
3891 		    if (joy_x < 12)
3892 		      joy_x++;
3893 		  }
3894 		  else if (option_line == 8)
3895 		  {
3896 		    if (joy_y < 12)
3897 		      joy_y++;
3898 		  }
3899 	        }
3900 	      else if (key == SDLK_SPACE || key == SDLK_RETURN)
3901 	        {
3902 		  done = 1;
3903 		}
3904 	    }
3905 	  else if (event.type == SDL_JOYBUTTONDOWN &&
3906 		   (num_joysticks < 2 || event.jbutton.which == player))
3907 	    {
3908 	      done = 1;
3909 	    }
3910 	  else if (event.type == SDL_QUIT)
3911 	    {
3912 	      quit = 1;
3913 	    }
3914 	}
3915 
3916 
3917       if (old_option_line != option_line)
3918 	{
3919 	  dest.x = 38 * 8;
3920 	  dest.y = (old_option_line + 11) * 10 - 1;
3921 	  dest.w = 8;
3922 	  dest.h = 10;
3923 
3924 	  SDL_FillRect(screen, &dest,
3925 		       SDL_MapRGB(screen->format, 0, 0, 0));
3926 	  write_num(38, old_option_line + 11, option_value(old_option_line));
3927 	  SDL_Flip(screen);
3928 	}
3929 
3930 
3931       /* Show current option: */
3932 
3933       write_num(44, 23, option_line);
3934 
3935       if ((frame % 20) < 10)
3936 	{
3937 	  dest.x = 38 * 8;
3938 	  dest.y = (option_line + 11) * 10 - 1;
3939 	  dest.w = 8;
3940 	  dest.h = 10;
3941 
3942 	  SDL_FillRect(screen, &dest,
3943 		       SDL_MapRGB(screen->format, 255, 255, 255));
3944 	  SDL_Flip(screen);
3945 	}
3946       else
3947 	{
3948 	  dest.x = 38 * 8;
3949 	  dest.y = (option_line + 11) * 10 - 1;
3950 	  dest.w = 8;
3951 	  dest.h = 10;
3952 
3953 	  SDL_FillRect(screen, &dest,
3954 		       SDL_MapRGB(screen->format, 0, 0, 0));
3955 	  write_num(38, option_line + 11, option_value(option_line));
3956 	  SDL_Flip(screen);
3957 	}
3958 
3959 
3960       /* Keep playing music: */
3961 
3962 #ifndef NOSOUND
3963       if (use_sound == 1)
3964         {
3965           if (!Mix_PlayingMusic())
3966 	    {
3967               Mix_PlayMusic(title_music, 0);
3968 	      Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
3969 	    }
3970         }
3971 #endif /* #ifndef NOSOUND */
3972 
3973 
3974       /* Pause til next frame: */
3975 
3976       if (SDL_GetTicks() < last_time + 33)
3977 	SDL_Delay(last_time + 33 - SDL_GetTicks());
3978     }
3979   while (!done && !quit);
3980 
3981   return(quit);
3982 }
3983 
3984 
3985 
3986 /* Title loop: */
3987 
title(void)3988 int title(void)
3989 {
3990   SDL_Rect dest, src;
3991   int done, i, option, old_option, count, impatience_count,
3992     angle, angle_m, angle_mm, angle_time, num_starfields, distortion;
3993   int old_axis;
3994   Uint32 last_time;
3995   SDL_Event event;
3996   SDLKey key;
3997 
3998 
3999   /* Reset starfields: */
4000 
4001   for (i = 0; i < MAX_STARFIELDS; i++)
4002     {
4003       starfields[i].radius = (rand() % 320) + 1;
4004       starfields[i].angle = (rand() % 360);
4005       starfields[i].time = (rand() % 32);
4006     }
4007 
4008   angle = 0;
4009   angle_m = 0;
4010   angle_mm = 0;
4011   angle_time = (rand() % 100) + 100;
4012 
4013   num_starfields = 1;
4014 
4015 
4016   /* MAIN TITLE SCREEN LOOP: */
4017 
4018   count = 0;
4019   done = 0;
4020   option = TITLE_OPTION_ONE_PLAYER;
4021   old_option = option;
4022   impatience_count = 0;
4023   distortion = 128;
4024   old_axis = 0;
4025 
4026   do
4027     {
4028       last_time = SDL_GetTicks();
4029 
4030 
4031       /* Check for keypresses: */
4032 
4033       while (SDL_PollEvent(&event))
4034 	{
4035 	  if (event.type == SDL_KEYDOWN)
4036 	    {
4037 	      key = event.key.keysym.sym;
4038 
4039 	      if (key == SDLK_ESCAPE)
4040 		{
4041 		  done = 1;
4042 		  option = TITLE_OPTION_QUIT;
4043 		}
4044 	      else if (key == SDLK_UP)
4045 		{
4046 		  if (option > 0)
4047 		    option--;
4048 		}
4049 	      else if (key == SDLK_DOWN)
4050 		{
4051 		  if (option < NUM_TITLE_OPTIONS - 1)
4052 		    option++;
4053 		}
4054 	      else if (key == SDLK_SPACE || key == SDLK_RETURN)
4055 		done = 1;
4056 	    }
4057 	  else if (event.type == SDL_JOYAXISMOTION &&
4058 		   event.jaxis.axis == joy_y)
4059 	    {
4060 	      if (event.jaxis.value < -256 && old_axis >= -128)
4061 		{
4062 		  if (option > 0)
4063 		    option--;
4064 		}
4065 	      else if (event.jaxis.value > 256 && old_axis <= 128)
4066 		{
4067 		  if (option < NUM_TITLE_OPTIONS - 1)
4068 		    option++;
4069 		}
4070 
4071 	      old_axis = event.jaxis.value;
4072 	    }
4073 	  else if (event.type == SDL_JOYBUTTONDOWN &&
4074 		   (num_joysticks < 2 || event.jbutton.which == player))
4075 	    {
4076 	      done = 1;
4077 	    }
4078 	  else if (event.type == SDL_QUIT)
4079 	    {
4080 	      done = 1;
4081 	      option = TITLE_OPTION_QUIT;
4082 	    }
4083 	}
4084 
4085 
4086       /* Move stars: */
4087 
4088       for (i = 0; i < MAX_STARFIELDS; i++)
4089 	{
4090 	  starfields[i].radius = (starfields[i].radius +
4091 				  ((32 - starfields[i].time) / 2));
4092 	  starfields[i].time--;
4093 
4094 	  if (starfields[i].radius >= 640 || starfields[i].time <= 0)
4095 	    {
4096 	      starfields[i].radius = (rand() % 320) + 1;
4097 	      starfields[i].angle = (rand() % 360);
4098 	      starfields[i].time = 32;
4099 	    }
4100 	}
4101 
4102 
4103       /* Rotate stars: */
4104 
4105       angle = angle + angle_m;
4106       if (angle >= 360)
4107 	angle = angle - 360;
4108       else if (angle <= 0)
4109 	angle = angle + 360;
4110 
4111       if ((count % 4) == 0)
4112 	angle_m = angle_m + angle_mm;
4113 
4114       angle_time--;
4115 
4116 
4117       /* Change rotation? */
4118 
4119       if (angle_time <= 0 || angle_m < -5 || angle_m > 5)
4120 	{
4121 	  if (angle_m < -5)
4122 	    {
4123 	      angle_m = -5;
4124 	      angle_mm = (rand() % 2);
4125 	    }
4126 	  else if (angle_m > 5)
4127 	    {
4128 	      angle_m = 5;
4129 	      angle_mm = -(rand() % 2);
4130 	    }
4131 	  else
4132 	    angle_mm = (rand() % 4) - 2;
4133 
4134 	  angle_time = (rand() % 100) + 100;
4135 	}
4136 
4137       if (num_starfields < MAX_STARFIELDS)
4138 	num_starfields++;
4139 
4140 
4141       /* Draw screen: */
4142 
4143       /* (Black): */
4144 
4145       SDL_FillRect(screen, NULL,
4146 		   SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
4147 
4148 
4149       /* (Starfield): */
4150 
4151       for (i = 0; i < num_starfields; i++)
4152 	{
4153 	  dest.x = (cos(M_PI * (angle + starfields[i].angle) / 180) *
4154 		    (starfields[i].radius)) + 320;
4155 	  dest.y = (-sin(M_PI * (angle + starfields[i].angle) / 180) *
4156 		    (starfields[i].radius)) + 240;
4157 	  dest.w = 1;
4158 	  dest.h = 1;
4159 
4160 	  src.x = 0;
4161 	  src.y = starfields[i].time;
4162 	  src.w = 1;
4163 	  src.h = 1;
4164 
4165 	  SDL_BlitSurface(images[IMG_TITLE_STARFIELD], &src, screen, &dest);
4166 	}
4167 
4168 
4169       /* (Title gfx): */
4170 
4171       if (distortion < 2)
4172 	{
4173 	  dest.x = (640 - (images[IMG_TITLE_TITLE] -> w)) / 2;
4174 	  dest.y = 0;
4175 	  dest.w = images[IMG_TITLE_TITLE] -> w;
4176 	  dest.h = images[IMG_TITLE_TITLE] -> h;
4177 
4178 	  SDL_BlitSurface(images[IMG_TITLE_TITLE], NULL, screen, &dest);
4179 	}
4180       else
4181 	{
4182 	  for (i = (count % (distortion / 2));
4183 	       i < images[IMG_TITLE_TITLE] -> h;
4184 	       i = i + (distortion / 2))
4185 	    {
4186 	      dest.x = (((640 - (images[IMG_TITLE_TITLE] -> w)) / 2) +
4187 			my_cos[(i + count) % 32] * distortion);
4188 	      dest.y = i;
4189 	      dest.w = images[IMG_TITLE_TITLE] -> w;
4190 	      dest.h = 1;
4191 
4192 	      src.x = 0;
4193 	      src.y = i;
4194 	      src.w = images[IMG_TITLE_TITLE] -> w;
4195 	      src.h = 1;
4196 
4197 	      SDL_BlitSurface(images[IMG_TITLE_TITLE], &src, screen, &dest);
4198 	    }
4199 
4200 	  distortion--;
4201 	}
4202 
4203 
4204       /* (Menu items): */
4205 
4206       for (i = 0; i < NUM_TITLE_OPTIONS; i++)
4207 	{
4208 	  dest.x = 224;
4209 	  dest.y = (images[IMG_TITLE_TITLE] -> h) + ((i + 3) * 32);
4210 	  dest.w = images[title_option_images[i]] -> w;
4211 	  dest.h = 32;
4212 
4213 	  SDL_BlitSurface(images[title_option_images[i]], NULL, screen, &dest);
4214 	}
4215 
4216 
4217       /* Play selection noise: */
4218 
4219       if (option != old_option)
4220 	{
4221 	  old_option = option;
4222 	  playsound(SND_SELECT, -1, 0);
4223 	}
4224 
4225 
4226       /* Animate the arrow: */
4227 
4228       count++;
4229 
4230 
4231       /* Draw the option selection arrow: */
4232 
4233       dest.x = 192;
4234       dest.y = (images[IMG_TITLE_TITLE] -> h) + ((option + 3) * 32);
4235       dest.w = 32;
4236       dest.h = 32;
4237 
4238       SDL_BlitSurface(images[IMG_TITLE_ARROW0 + (count / 10) % 3],
4239 		      NULL, screen, &dest);
4240 
4241 
4242       /* Draw the last game's scores: */
4243 
4244       if (score[0] != -1)
4245 	{
4246 	  write_text(0, 45, "PLAYER 1");
4247 	  write_num(0, 46, level[0]);
4248 	  write_num(0, 47, score[0]);
4249 	}
4250 
4251       write_text(35, 45, "HIGH SCORE");
4252       write_num(37, 46, highscore);
4253 
4254       if (score[1] != -1)
4255 	{
4256 	  write_text(72, 45, "PLAYER 2");
4257 	  write_num(72, 46, level[1]);
4258 	  write_num(72, 47, score[1]);
4259 	}
4260 
4261 
4262       SDL_Flip(screen);
4263 
4264 
4265       /* Keep playing music: */
4266 
4267 #ifndef NOSOUND
4268       if (use_sound == 1)
4269         {
4270           if (!Mix_PlayingMusic())
4271 	    {
4272               Mix_PlayMusic(title_music, 0);
4273 	      Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
4274 	    }
4275         }
4276 #endif /* #ifndef NOSOUND */
4277 
4278 
4279       impatience_count++;
4280 
4281       if (impatience_count >= 600)
4282 	{
4283 	  impatience_count = 0;
4284 	  playsound(SND_IMPATIENCE, 0, 1);
4285 	}
4286 
4287 
4288       /* Pause til next frame: */
4289 
4290       if (SDL_GetTicks() < last_time + 33)
4291 	SDL_Delay(last_time + 33 - SDL_GetTicks());
4292     }
4293   while (done == 0);
4294 
4295 
4296   playsound(SND_CONFIRM, 0, 1);
4297 
4298   SDL_Delay(200);
4299 
4300   return (option);
4301 }
4302 
4303 
4304 /* Setup: */
4305 
setup(void)4306 void setup(void)
4307 {
4308   int i, done, distortion, distortion_m;
4309   Uint32 old_ticks, last_time;
4310   SDL_Surface * image;
4311   SDL_Rect dest, src;
4312   SDL_Event event;
4313 
4314 
4315   /* Init SDL Video: */
4316 
4317   if (SDL_Init(SDL_INIT_VIDEO) < 0)
4318     {
4319       fprintf(stderr,
4320               "\nError: I could not initialize video!\n"
4321               "The Simple DirectMedia error that occured was:\n"
4322               "%s\n\n", SDL_GetError());
4323       exit(1);
4324     }
4325   atexit(SDL_Quit);
4326 
4327 
4328   /* Open display: */
4329 
4330   if (use_fullscreen == 1)
4331     {
4332       screen = set_vid_mode(SDL_FULLSCREEN);
4333       if (screen == NULL)
4334         {
4335           fprintf(stderr,
4336                   "\nWarning: I could not set up fullscreen video for "
4337                   "640x480 mode.\n"
4338                   "The Simple DirectMedia error that occured was:\n"
4339                   "%s\n\n", SDL_GetError());
4340           use_fullscreen = 0;
4341         }
4342     }
4343 
4344 
4345   if (use_fullscreen == 0)
4346     {
4347       screen = set_vid_mode(0);
4348 
4349       if (screen == NULL)
4350         {
4351           fprintf(stderr,
4352                   "\nError: I could not set up video for 640x480 mode.\n"
4353                   "The Simple DirectMedia error that occured was:\n"
4354                   "%s\n\n", SDL_GetError());
4355           exit(1);
4356         }
4357     }
4358 
4359 
4360 #ifndef NOSOUND
4361   /* Open sound: */
4362 
4363   if (use_sound == 1)
4364     {
4365       if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
4366         {
4367           fprintf(stderr,
4368                   "\nWarning: I could not set up audio for 22050 Hz "
4369                   "16-bit stereo.\n"
4370                   "The Simple DirectMedia error that occured was:\n"
4371                   "%s\n\n", SDL_GetError());
4372           use_sound = 0;
4373         }
4374     }
4375 
4376   for (i = 0; i < 4; i++)
4377     dontblockchan[i] = 0;
4378 
4379   Mix_Volume(-1, vol_effects * (MIX_MAX_VOLUME / 5));
4380   Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
4381 #endif /* #ifndef NOSOUND */
4382 
4383 
4384   use_joystick = 1;
4385   num_joysticks = 0;
4386 
4387 
4388   /* Init joystick: */
4389 
4390   if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
4391     {
4392       fprintf(stderr,
4393 	      "\nWarning: I could not initialize joystick.\n"
4394 	      "The Simple DirectMedia error that occured was:\n"
4395 	      "%s\n\n", SDL_GetError());
4396 
4397       use_joystick = 0;
4398     }
4399   else
4400     {
4401       /* Look for joysticks: */
4402 
4403       num_joysticks = SDL_NumJoysticks();
4404 
4405       if (num_joysticks <= 0)
4406 	{
4407 	  fprintf(stderr,
4408 		  "\nWarning: No joysticks available.\n");
4409 
4410 	  use_joystick = 0;
4411 	}
4412       else
4413 	{
4414 	  /* Open joystick: */
4415 
4416 	  js = SDL_JoystickOpen(0);
4417 
4418 	  if (js == NULL)
4419 	    {
4420 	      fprintf(stderr,
4421 		      "\nWarning: Could not open joystick 1.\n"
4422 		      "The Simple DirectMedia error that occured was:\n"
4423 		      "%s\n\n", SDL_GetError());
4424 
4425 	      use_joystick = 0;
4426 	    }
4427 	  else
4428 	    {
4429 	      /* Check for proper stick configuration: */
4430 
4431 	      if (SDL_JoystickNumAxes(js) < 2)
4432 		{
4433 		  fprintf(stderr,
4434 			  "\nWarning: Joystick doesn't have enough axes!\n");
4435 
4436 		  use_joystick = 0;
4437 		}
4438 	      else
4439 		{
4440 		  if (SDL_JoystickNumButtons(js) < 2)
4441 		    {
4442 		      fprintf(stderr,
4443 			      "\nWarning: Joystick doesn't have enough "
4444 			      "buttons!\n");
4445 
4446 		      use_joystick = 0;
4447 		    }
4448 		}
4449 	    }
4450 	}
4451     }
4452 
4453 
4454   /* Set window manager stuff: */
4455 
4456   SDL_WM_SetCaption("Defendguin", "Defendguin");
4457 
4458 
4459   /* Load graphics: */
4460 
4461   old_ticks = (Uint32) 0;
4462   flash = 0;
4463 
4464   for (i = 0; i < NUM_IMAGES; i++)
4465     {
4466       image = SDL_LoadBMP(image_names[i]);
4467 
4468       if (image == NULL)
4469 	{
4470 	  fprintf(stderr,
4471 		  "\nError: I couldn't load a graphics file:\n"
4472 		  "%s\n"
4473 		  "The Simple DirectMedia error that occured was:\n"
4474 		  "%s\n\n", image_names[i], SDL_GetError());
4475 	  exit(1);
4476 	}
4477 
4478 
4479       /* Convert to display format: */
4480 
4481       images[i] = SDL_DisplayFormat(image);
4482       if (images[i] == NULL)
4483         {
4484           fprintf(stderr,
4485                   "\nError: I couldn't convert a file to the display format:\n"
4486                   "%s\n"
4487                   "The Simple DirectMedia error that occured was:\n"
4488                   "%s\n\n", image_names[i], SDL_GetError());
4489           exit(1);
4490         }
4491 
4492 
4493       /* Set transparency: */
4494 
4495       if (i != 0)
4496 	{
4497 	  if (SDL_SetColorKey(images[i], (SDL_SRCCOLORKEY | SDL_RLEACCEL),
4498 			      SDL_MapRGB(images[i] -> format,
4499 					 0xFF, 0xFF, 0xFF)) == -1)
4500 	    {
4501 	      fprintf(stderr,
4502 		      "\nError: I could not set the color key for the file:\n"
4503 		      "%s\n"
4504 		      "The Simple DirectMedia error that occured was:\n"
4505 		      "%s\n\n", image_names[i], SDL_GetError());
4506 	      exit(1);
4507 	    }
4508 	}
4509 
4510 
4511       if (i == 0)
4512 	{
4513 	  /* Draw "loading" background: */
4514 
4515 	  SDL_BlitSurface(images[IMG_LOADING], NULL, screen, NULL);
4516 	  SDL_UpdateRect(screen, 0, 0, 640, 480);
4517 	}
4518       else if (i >= 1)
4519 	{
4520 	  /* Flash "...loading..." text: */
4521 
4522 	  if (SDL_GetTicks() > old_ticks + 50)
4523 	    {
4524 	      old_ticks = SDL_GetTicks();
4525 
4526 	      flash = 1 - flash;
4527 
4528 	      dest.x = (640 - (images[1] -> w)) / 2;
4529 	      dest.y = 480 - (images[1] -> h);
4530 	      dest.w = images[1] -> w;
4531 	      dest.h = images[1] -> h;
4532 
4533 	      if (flash == 1)
4534 		SDL_BlitSurface(images[IMG_LOADING_TEXT], NULL, screen, &dest);
4535 	      else
4536 		SDL_BlitSurface(images[IMG_LOADING], &dest, screen, &dest);
4537 
4538 	      SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
4539 	    }
4540 	}
4541 
4542       SDL_FreeSurface(image);
4543     }
4544 
4545 
4546 #ifndef NOSOUND
4547   if (use_sound == 1)
4548     {
4549       /* Load sounds: */
4550 
4551       for (i = 0; i < NUM_SOUNDS; i++)
4552 	{
4553 	  sounds[i] = Mix_LoadWAV(sound_names[i]);
4554 	  if (sounds[i] == NULL)
4555 	    {
4556 	      fprintf(stderr,
4557 		      "\nError: I could not load the sound file:\n"
4558 		      "%s\n"
4559 		      "The Simple DirectMedia error that occured was:\n"
4560 		      "%s\n\n", sound_names[i], SDL_GetError());
4561 	      exit(1);
4562 	    }
4563 
4564 	  /* Flash "...loading..." text: */
4565 
4566 	  if (SDL_GetTicks() > old_ticks + 50)
4567 	    {
4568 	      old_ticks = SDL_GetTicks();
4569 
4570 	      flash = 1 - flash;
4571 
4572 	      dest.x = (640 - (images[1] -> w)) / 2;
4573 	      dest.y = 480 - (images[1] -> h);
4574 	      dest.w = images[1] -> w;
4575 	      dest.h = images[1] -> h;
4576 
4577 	      if (flash == 1)
4578 		SDL_BlitSurface(images[IMG_LOADING_TEXT], NULL, screen, &dest);
4579 	      else
4580 		SDL_BlitSurface(images[IMG_LOADING], &dest, screen, &dest);
4581 
4582 	      SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
4583 	    }
4584 	}
4585 
4586 
4587       /* Load music: */
4588 
4589       title_music = Mix_LoadMUS(MUS_TITLE);
4590       if (title_music == NULL)
4591         {
4592           fprintf(stderr,
4593                   "\nError: I could not load the music file:\n"
4594                   "%s\n"
4595                   "The Simple DirectMedia error that occured was:\n"
4596                   "%s\n\n", MUS_TITLE, SDL_GetError());
4597           exit(1);
4598         }
4599       Mix_PlayMusic(title_music, 0);
4600       Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
4601 
4602 
4603       last_music = Mix_LoadMUS(MUS_LAST);
4604       if (last_music == NULL)
4605         {
4606           fprintf(stderr,
4607                   "\nError: I could not load the music file:\n"
4608                   "%s\n"
4609                   "The Simple DirectMedia error that occured was:\n"
4610                   "%s\n\n", MUS_LAST, SDL_GetError());
4611           exit(1);
4612         }
4613 
4614 
4615       win_music = Mix_LoadMUS(MUS_WIN);
4616       if (win_music == NULL)
4617         {
4618           fprintf(stderr,
4619                   "\nError: I could not load the music file:\n"
4620                   "%s\n"
4621                   "The Simple DirectMedia error that occured was:\n"
4622                   "%s\n\n", MUS_WIN, SDL_GetError());
4623           exit(1);
4624         }
4625 
4626 
4627       for (i = 0; i < NUM_GAME_MUSICS; i++)
4628         {
4629           game_musics[i] = Mix_LoadMUS(game_music_names[i]);
4630           if (game_musics[i] == NULL)
4631             {
4632               fprintf(stderr,
4633                       "\nError: I could not load the music file:\n"
4634                       "%s\n"
4635                       "The Simple DirectMedia error that occured was:\n"
4636                       "%s\n\n", game_music_names[i], SDL_GetError());
4637               exit(1);
4638             }
4639         }
4640     }
4641 #endif /* #ifndef NOSOUND */
4642 
4643 
4644   /* Erase "Loading": */
4645 
4646   dest.x = (640 - (images[1] -> w)) / 2;
4647   dest.y = 480 - (images[1] -> h);
4648   dest.w = images[1] -> w;
4649   dest.h = images[1] -> h;
4650 
4651   SDL_BlitSurface(images[IMG_LOADING], &dest, screen, &dest);
4652   SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
4653 
4654 
4655   /* Initialize random seed: */
4656 
4657   srand(SDL_GetTicks());
4658 
4659 
4660   /* Initialize cosine wave: */
4661 
4662   for (i = 0; i < 32; i++)
4663     {
4664       my_cos[i] = cos(M_PI * (i * 11) / 180);
4665     }
4666 
4667 
4668   /* Draw some informative text: */
4669 
4670   write_centered_text(33, "RELEASE " VERSION);
4671 
4672 
4673   /* Flash "Press a key" on the screen (yes, I'm _really_ proud of the
4674      loading screen art! :) ) */
4675 
4676   done = 0;
4677   distortion = 0;
4678   distortion_m = 1;
4679 
4680   do
4681     {
4682       last_time = SDL_GetTicks();
4683 
4684 
4685       /* Check for keypresses: */
4686 
4687       while (SDL_PollEvent(&event))
4688 	{
4689 	  if (event.type == SDL_KEYDOWN)
4690 	    done = 1;
4691 
4692 	  if (event.type == SDL_JOYBUTTONDOWN &&
4693 	      (num_joysticks < 2 || event.jbutton.which == player))
4694 	    {
4695 	      done = 1;
4696 	    }
4697 	}
4698 
4699 
4700       dest.x = 0;
4701       dest.y = 480 - (images[IMG_PRESS_A_KEY] -> h);
4702       dest.w = 640;
4703       dest.h = images[IMG_PRESS_A_KEY] -> h;
4704 
4705       SDL_BlitSurface(images[0], &dest, screen, &dest);
4706 
4707 
4708       /* Draw fuzzy text behind: */
4709 
4710       distortion = distortion + distortion_m;
4711       if (distortion == 0)
4712 	distortion_m = 1;
4713       else if (distortion == 64)
4714 	distortion_m = -1;
4715 
4716       for (i = (flash % 2); i < images[IMG_PRESS_A_KEY] -> h; i = i + 2)
4717 	{
4718 	  dest.x = (((640 - (images[IMG_PRESS_A_KEY] -> w)) / 2) +
4719 		    my_cos[(i + flash) % 32] * distortion);
4720 	  dest.y = 480 - (images[IMG_PRESS_A_KEY] -> h) + i;
4721 	  dest.w = images[IMG_PRESS_A_KEY] -> w;
4722 	  dest.h = 1;
4723 
4724 	  src.x = 0;
4725 	  src.y = i;
4726 	  src.w = images[IMG_PRESS_A_KEY] -> w;
4727 	  src.h = 1;
4728 
4729 	  SDL_BlitSurface(images[IMG_PRESS_A_KEY], &src, screen, &dest);
4730 	}
4731 
4732 
4733       /* Flash the image: */
4734 
4735       flash++;
4736 
4737       dest.x = (640 - (images[IMG_PRESS_A_KEY] -> w)) / 2;
4738       dest.y = 480 - (images[IMG_PRESS_A_KEY] -> h);
4739       dest.w = images[IMG_PRESS_A_KEY] -> w;
4740       dest.h = images[IMG_PRESS_A_KEY] -> h;
4741 
4742       if (flash < 15)
4743 	SDL_BlitSurface(images[IMG_PRESS_A_KEY], NULL, screen, &dest);
4744       else if (flash == 30)
4745 	flash = 0;
4746 
4747       SDL_UpdateRect(screen, 0, dest.y, 640, dest.h);
4748 
4749 
4750       /* Pause til next frame: */
4751 
4752       if (SDL_GetTicks() < last_time + 33)
4753 	SDL_Delay(last_time + 33 - SDL_GetTicks());
4754 
4755 #ifndef NOSOUND
4756       if (use_sound == 1)
4757 	{
4758 	  if (Mix_PlayingMusic() == 0)
4759 	    {
4760 	      Mix_PlayMusic(title_music, 0);
4761 	      Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
4762 	    }
4763 	}
4764 #endif /* #ifndef NOSOUND */
4765     }
4766   while (done == 0);
4767 }
4768 
4769 
4770 /* Set video mode: */
4771 /* Mattias Engdegard <f91-men@nada.kth.se> */
4772 
set_vid_mode(unsigned flags)4773 SDL_Surface * set_vid_mode(unsigned flags)
4774 {
4775   /* Prefer 16bpp, but also prefer native modes to emulated 16bpp. */
4776 
4777   int depth;
4778 
4779   depth = SDL_VideoModeOK(640, 480, 16, flags);
4780   return depth ? SDL_SetVideoMode(640, 480, depth, flags) : NULL;
4781 }
4782 
4783 
4784 /* Quit! */
4785 
my_shutdown(void)4786 void my_shutdown(void)
4787 {
4788 #ifndef NOSOUND
4789   if (use_sound == 1)
4790     {
4791       Mix_HaltMusic();
4792       Mix_HaltChannel(-1);
4793     }
4794 #endif /* #ifndef NOSOUND */
4795 
4796   SDL_Quit();
4797 }
4798 
4799 
4800 /* Create landscape: */
4801 
create_land(int ply)4802 void create_land(int ply)
4803 {
4804   int x, y, height, old_height, first_height;
4805 
4806   old_height = 0;
4807   height = (rand() % (LAND_HEIGHT - LAND_MIN_HEIGHT) + LAND_MIN_HEIGHT);
4808   first_height = height;
4809 
4810   for (x = 0; x < LAND_WIDTH - (LAND_HEIGHT / 2); x++)
4811     {
4812       for (y = 0; y < LAND_HEIGHT; y++)
4813 	{
4814 	  if (height < y)
4815 	    land[ply][x][y] = IMG_LAND_CENTER;
4816 	  else if (height == y)
4817 	    {
4818 	      if (height > old_height)
4819 		{
4820 		  land[ply][x][y - 1] = IMG_LAND_RIGHT;
4821 		  land[ply][x][y] = IMG_LAND_CENTER;
4822 		}
4823 	      else if (height < old_height)
4824 		land[ply][x][y] = IMG_LAND_LEFT;
4825 	      else
4826 		land[ply][x][y] = IMG_LAND_CENTER;
4827 	    }
4828 	  else
4829 	    land[ply][x][y] = -1;
4830 	}
4831 
4832       old_height = height;
4833 
4834       if ((rand() % 3) != 0)
4835 	{
4836 	  if ((rand() % 2) == 0)
4837 	    height++;
4838 	  else
4839 	    height--;
4840 	}
4841 
4842       if (height < LAND_MIN_HEIGHT)
4843 	height = height + 2;
4844       else if (height >= LAND_HEIGHT)
4845 	height = height - 2;
4846     }
4847 
4848   for (x = LAND_WIDTH - (LAND_HEIGHT / 2); x < LAND_WIDTH; x++)
4849     {
4850       for (y = 0; y < LAND_HEIGHT; y++)
4851 	{
4852 	  if (height < y)
4853 	    land[ply][x][y] = IMG_LAND_CENTER;
4854 	  else if (height == y)
4855 	    {
4856 	      if (height > old_height)
4857 		{
4858 		  land[ply][x][y - 1] = IMG_LAND_RIGHT;
4859 		  land[ply][x][y] = IMG_LAND_CENTER;
4860 		}
4861 	      else if (height < old_height)
4862 		land[ply][x][y] = IMG_LAND_LEFT;
4863 	      else
4864 		land[ply][x][y] = IMG_LAND_CENTER;
4865 	    }
4866 	  else
4867 	    land[ply][x][y] = -1;
4868 	}
4869 
4870       old_height = height;
4871 
4872       if (height > first_height - 1)
4873 	height--;
4874       else if (height < first_height - 1)
4875 	height++;
4876     }
4877 }
4878 
4879 
4880 /* Create friendly penguinoids: */
4881 
create_penguinoids(int ply,int num)4882 void create_penguinoids(int ply, int num)
4883 {
4884   int i;
4885 
4886   for (i = 0; i < MAX_PENGUINOIDS; i++)
4887     {
4888       if (i < num)
4889 	{
4890 	  penguinoids[ply][i].alive = 1;
4891 	  penguinoids[ply][i].mode = PENG_MODE_WALKING;
4892 	  penguinoids[ply][i].being_homed = 0;
4893 	  penguinoids[ply][i].x = (rand() % (LAND_WIDTH * 32));
4894 	  penguinoids[ply][i].y = 480 - 32;
4895 
4896 	  penguinoids[ply][i].xm = 1;
4897 	  if ((rand() % 2) == 0)
4898 	    penguinoids[ply][i].xm = -penguinoids[ply][i].xm;
4899 
4900 	  penguinoids[ply][i].ym = 1;
4901 	  if ((rand() % 2) == 0)
4902 	    penguinoids[ply][i].ym = -penguinoids[ply][i].ym;
4903 	}
4904       else
4905 	penguinoids[ply][i].alive = 0;
4906     }
4907 }
4908 
4909 
4910 /* Draw a number on the screen: */
4911 
draw_number(int x,int y,int n)4912 void draw_number(int x, int y, int n)
4913 {
4914   char str[16];
4915   SDL_Rect src, dest;
4916   int i;
4917 
4918 
4919   if (n == 0)
4920     strcpy(str, "    00");
4921   else
4922     sprintf(str, "%6d", n);
4923 
4924   for (i = 0; i < strlen(str); i++)
4925     {
4926       dest.x = x + i * 24;
4927       dest.y = y;
4928       dest.w = 24;
4929       dest.h = 32;
4930 
4931       src.x = (str[i] - '0') * 24;
4932       src.y = 0;
4933       src.w = 24;
4934       src.h = 32;
4935 
4936       SDL_BlitSurface(images[IMG_NUMBERS], &src, screen, &dest);
4937     }
4938 }
4939 
4940 
4941 /* Add an alien: */
4942 
add_alien(int x,int y,int type,int mode,int timer)4943 void add_alien(int x, int y, int type, int mode, int timer)
4944 {
4945   int i, found;
4946 
4947 
4948   /* Look for a slot in the aliens array: */
4949 
4950   found = -1;
4951 
4952   for (i = 0; i < MAX_ALIENS && found == -1; i++)
4953     {
4954       if (aliens[player][i].alive == 0)
4955 	found = i;
4956     }
4957 
4958 
4959   /* Pick random spots, if x and/or y are set to -1: */
4960 
4961   if (x == -1)
4962     x = (rand() % (LAND_WIDTH * 32));
4963 
4964   if (y == -1)
4965     y = (rand() % 240) + 80;
4966 
4967 
4968   /* Add the mine! */
4969 
4970   if (found != -1)
4971     {
4972       aliens[player][found].alive = 1;
4973 
4974       if (planet_dead[player] == 0 ||
4975 	  type == ALIEN_MINE || type == ALIEN_BAITER ||
4976 	  type == ALIEN_EVILBILL)
4977 	aliens[player][found].type = type;
4978       else
4979 	aliens[player][found].type = ALIEN_MUTANT;
4980 
4981       aliens[player][found].mode = mode;
4982       aliens[player][found].shields = 20;
4983 
4984       aliens[player][found].x = x;
4985       aliens[player][found].y = y;
4986 
4987       aliens[player][found].xm = (rand() % 4) + 1;
4988       if ((rand() % 2) == 0)
4989 	aliens[player][found].xm = -aliens[player][found].xm;
4990 
4991       aliens[player][found].xmm = 1;
4992 
4993       aliens[player][found].ym = (rand() % 4) + 1;
4994       if ((rand() % 2) == 0)
4995 	aliens[player][found].ym = -aliens[player][found].ym;
4996 
4997       aliens[player][found].ymm = 1;
4998 
4999       aliens[player][found].ym = 0;
5000       aliens[player][found].timer = timer;
5001     }
5002 }
5003 
5004 
5005 /* Create stars: */
5006 
create_stars(void)5007 void create_stars(void)
5008 {
5009   int i;
5010 
5011   for (i = 0; i < MAX_STARS; i++)
5012     {
5013       stars[i].x = (rand() % (LAND_WIDTH * 16));
5014       stars[i].y = (rand() % 400) + 80;
5015     }
5016 }
5017 
5018 
5019 /* Add a laser shot: */
5020 
add_laser(int x,int y,int dir)5021 void add_laser(int x, int y, int dir)
5022 {
5023   int i, found;
5024 
5025 
5026   /* Find a free laser slot: */
5027 
5028   found = -1;
5029 
5030   for (i = 0; i < MAX_LASERS && found == -1; i++)
5031     {
5032       if (lasers[i].alive == 0)
5033 	found = i;
5034     }
5035 
5036 
5037   /* Turn on the laser shot: */
5038 
5039   if (found != -1)
5040     {
5041       lasers[found].alive = 1;
5042 
5043 
5044       if (dir == DIR_RIGHT)
5045 	x = x + 32 - LASER_SPEED;
5046       else if (dir == DIR_LEFT)
5047 	x = x + 32 + LASER_SPEED;
5048 
5049       lasers[found].x1 = x;
5050 
5051       if (dir == DIR_RIGHT)
5052 	lasers[found].x2 = 640;
5053       else
5054 	lasers[found].x2 = 0;
5055 
5056       lasers[found].y = y;
5057     }
5058 }
5059 
5060 
5061 /* Play a sound: */
5062 
playsound(int snd,int chan,int blocking)5063 void playsound(int snd, int chan, int blocking)
5064 {
5065 #ifndef NOSOUND
5066   if (use_sound == 1)
5067     {
5068       if (chan == -1 || blocking == 1 ||
5069 	  Mix_Playing(chan) == 0 || dontblockchan[chan] == 0)
5070 	{
5071 	  chan = Mix_PlayChannel(chan, sounds[snd], 0);
5072 	  dontblockchan[chan] = blocking;
5073 	}
5074     }
5075 #endif /* #ifndef NOSOUND */
5076 }
5077 
5078 
5079 /* Add an explosion: */
5080 
add_explosion(int x,int y,int img)5081 void add_explosion(int x, int y, int img)
5082 {
5083   add_explosion_bit(x, y, 0, -4, img);
5084   add_explosion_bit(x, y, 2, -2, img);
5085   add_explosion_bit(x, y, 4, 0, img);
5086   add_explosion_bit(x, y, 2, 2, img);
5087   add_explosion_bit(x, y, 0, 4, img);
5088   add_explosion_bit(x, y, -2, 2, img);
5089   add_explosion_bit(x, y, -4, 0, img);
5090   add_explosion_bit(x, y, -2, -2, img);
5091 }
5092 
5093 
5094 /* Add a bit of explosion: */
5095 
add_explosion_bit(int x,int y,int xm,int ym,int img)5096 void add_explosion_bit(int x, int y, int xm, int ym, int img)
5097 {
5098   int i, found;
5099 
5100   /* Find an explosion slot: */
5101 
5102   found = -1;
5103 
5104   for (i = 0; i < MAX_EXPLOSION_BITS && found == -1; i++)
5105     {
5106       if (explosion_bits[i].alive == 0)
5107 	found = i;
5108     }
5109 
5110 
5111   /* Add the bit: */
5112 
5113   if (found != -1)
5114     {
5115       explosion_bits[found].alive = 1;
5116       explosion_bits[found].x = x;
5117       explosion_bits[found].y = y;
5118       explosion_bits[found].xm = xm;
5119       explosion_bits[found].ym = ym;
5120       explosion_bits[found].time = 50;
5121       explosion_bits[found].img = img;
5122     }
5123 }
5124 
5125 
5126 /* Add points: */
5127 
add_points(int xx,int yy,int img)5128 void add_points(int xx, int yy, int img)
5129 {
5130   int i, found, oldest, oldest_time, realx;
5131 
5132 
5133   /* Find a free (or the oldest) slot: */
5134 
5135   found = -1;
5136   oldest = 0;
5137   oldest_time = 1000;
5138 
5139   for (i = 0; i < MAX_POINTS && found == -1; i++)
5140     {
5141       if (points[i].alive == 0)
5142 	found = i;
5143 
5144       if (points[i].time < oldest_time)
5145 	{
5146 	  oldest_time = points[i].time;
5147 	  oldest = i;
5148 	}
5149     }
5150 
5151 
5152   /* If there was no free, pick the oldest slot: */
5153 
5154   if (found == -1)
5155     found = oldest;
5156 
5157 
5158   /* Determine a screen position: */
5159 
5160   realx = xx - (x[player] - scroll[player]);
5161 
5162   if (realx < -31)
5163     realx = realx + (LAND_WIDTH * 32);
5164 
5165   while (realx >= (LAND_WIDTH * 32))
5166     realx = realx - (LAND_WIDTH * 32);
5167 
5168 
5169   /* Turn on the points bit: */
5170 
5171   points[found].alive = 1;
5172   points[found].x = realx;
5173   points[found].y = yy;
5174   points[found].time = 30;
5175   points[found].img = img;
5176 }
5177 
5178 
5179 /* Add flame: */
5180 
add_flame(int x,int y)5181 void add_flame(int x, int y)
5182 {
5183   int i, found;
5184 
5185 
5186   /* Find a free slot: */
5187 
5188   found = -1;
5189 
5190   for (i = 0; i < MAX_FLAMES && found == -1; i++)
5191     {
5192       if (flames[i].alive == 0)
5193 	found = i;
5194     }
5195 
5196 
5197   /* Turn on the flame: */
5198 
5199   if (found != -1)
5200     {
5201       flames[found].alive = 1;
5202       flames[found].x = x;
5203       flames[found].y = y;
5204       flames[found].xm = (rand() % 10) - 5;
5205       flames[found].time = 11;
5206     }
5207 }
5208 
5209 
5210 /* Kill a particular alien (add points, explosion, release penguinoids): */
5211 
kill_alien(int i)5212 void kill_alien(int i)
5213 {
5214   int j;
5215 
5216   if (aliens[player][i].type != ALIEN_EVILBILL ||
5217       aliens[player][i].y >= 480)
5218     {
5219       aliens[player][i].alive = 0;
5220 
5221       j = IMG_LASERS;
5222 
5223       if (aliens[player][i].type == ALIEN_UFO)
5224 	j = IMG_UFO0;
5225       else if (aliens[player][i].type == ALIEN_MUTANT)
5226 	j = IMG_LASERS;
5227       else if (aliens[player][i].type == ALIEN_POD)
5228 	j = IMG_POD0;
5229       else if (aliens[player][i].type == ALIEN_SWARMER)
5230 	j = IMG_SWARMER;
5231       else if (aliens[player][i].type == ALIEN_BOMBER)
5232 	j = IMG_BOMBER;
5233 
5234       add_explosion(aliens[player][i].x + 16, aliens[player][i].y + 16, j);
5235 
5236       playsound(SND_EXPLODE, 3, 0);
5237 
5238 
5239       /* How many points is it worth? */
5240 
5241       if (aliens[player][i].type == ALIEN_UFO ||
5242 	  aliens[player][i].type == ALIEN_MUTANT ||
5243 	  aliens[player][i].type == ALIEN_SWARMER)
5244 	{
5245 	  add_score(150);
5246 	  add_points(aliens[player][i].x, aliens[player][i].y,
5247 		     IMG_150);
5248 	}
5249       else if (aliens[player][i].type == ALIEN_BOMBER)
5250 	{
5251 	  add_score(250);
5252 	  add_points(aliens[player][i].x, aliens[player][i].y,
5253 		     IMG_250);
5254 	}
5255       else if (aliens[player][i].type == ALIEN_BAITER)
5256 	{
5257 	  add_score(200);
5258 	  add_points(aliens[player][i].x, aliens[player][i].y,
5259 		     IMG_200);
5260 	}
5261       else if (aliens[player][i].type == ALIEN_POD)
5262 	{
5263 	  add_score(1000);
5264 	  add_points(aliens[player][i].x, aliens[player][i].y,
5265 		     IMG_1000);
5266 	}
5267 
5268 
5269       /* If it was a UFO and was beaming a penguin,
5270 	 release the penguin: */
5271 
5272       if (aliens[player][i].mode == ALIEN_MODE_HOME_PENG ||
5273 	  aliens[player][i].mode == ALIEN_MODE_CAPTURED_PENG ||
5274 	  aliens[player][i].mode == ALIEN_MODE_BEAMING_PENG)
5275 	{
5276 	  penguinoids[player][aliens[player][i].home_peng].mode =
5277 	    PENG_MODE_FALLING;
5278 	  penguinoids[player][aliens[player][i].home_peng].being_homed = 0;
5279 	  penguinoids[player][aliens[player][i].home_peng].ym = 1;
5280 	  set_message(IMG_CATCH_THE_PENGUINOID);
5281 	}
5282 
5283 
5284       /* Was it Evil Bill? */
5285 
5286       if (aliens[player][i].type == ALIEN_EVILBILL)
5287 	{
5288 	  /* Do an interesting implosion effect: */
5289 
5290 	  for (j = 0; j < MAX_EXPLOSION_BITS; j++)
5291 	    {
5292 	      if (explosion_bits[j].alive)
5293 		{
5294 		  explosion_bits[j].xm = -explosion_bits[j].xm;
5295 		  explosion_bits[j].ym = -explosion_bits[j].ym;
5296 		}
5297 	    }
5298 
5299 
5300 	  /* Get ready for winning music: */
5301 
5302 #ifndef NOSOUND
5303 	  if (use_sound == 1)
5304 	    {
5305 	      Mix_HaltMusic();
5306 	    }
5307 #endif /* #ifndef NOSOUND */
5308 
5309 
5310 	  /* Kill all other aliens (mines): */
5311 
5312 	  for (j = 0; j < MAX_ALIENS; j++)
5313 	    {
5314 	      aliens[player][j].alive = 0;
5315 	    }
5316 	}
5317     }
5318   else
5319     {
5320       /* Hurt Evil Bill: */
5321 
5322       aliens[player][i].mode = ALIEN_MODE_HURTING;
5323       aliens[player][i].timer = 10;
5324 
5325       aliens[player][i].shields--;
5326 
5327 
5328       if (aliens[player][i].shields <= 0)
5329 	{
5330 	  /* Shields dead!  Kill! */
5331 
5332 	  aliens[player][i].mode = ALIEN_MODE_DYING;
5333 	  aliens[player][i].ym = -5;
5334 	  playsound(SND_EVILBILL_DIE, 1, 1);
5335 
5336 	  dancing[player] = 1;
5337 
5338 	  add_score(50000);
5339 	}
5340       else if (aliens[player][i].shields >= 8 && aliens[player][i].shields <= 10)
5341 	{
5342 	  /* Shields low: */
5343 
5344 	  playsound(SND_EVILBILL_LOW, 1, 0);
5345 	  add_score(100);
5346 	}
5347       else
5348 	{
5349 	  /* "Ow!" */
5350 
5351 	  playsound(SND_EVILBILL_HURT, 1, 0);
5352 	  add_score(100);
5353 	}
5354     }
5355 }
5356 
5357 
5358 /* Add a bullet: */
5359 
add_bullet(int xx,int yy,int owner)5360 void add_bullet(int xx, int yy, int owner)
5361 {
5362   int i, found;
5363 
5364 
5365   /* Find a slot: */
5366 
5367   found = -1;
5368 
5369   for (i = 0; i < MAX_BULLETS && found == -1; i++)
5370     {
5371       if (bullets[i].alive == 0)
5372 	found = i;
5373     }
5374 
5375 
5376   /* Turn the bullet on: */
5377 
5378   if (found != -1)
5379     {
5380       bullets[found].alive = 1;
5381       bullets[found].timer = 50;
5382       bullets[found].owner = owner;
5383 
5384       bullets[found].x = xx;
5385       bullets[found].y = yy;
5386 
5387       bullets[found].xm = (x[player] - xx) / 40;
5388       bullets[found].ym = (y[player] - yy) / 40;
5389 
5390       playsound(SND_BULLET, 1, 0);
5391     }
5392 }
5393 
5394 
5395 /* Set the current message: */
5396 
set_message(int img)5397 void set_message(int img)
5398 {
5399   mesg_img = img;
5400   mesg_timer = 50;
5401 }
5402 
5403 
5404 /* Kill the player: */
5405 
kill_player(void)5406 void kill_player(void)
5407 {
5408   int i;
5409 
5410 
5411   /* Make the player die, and the screen flash and some noise: */
5412 
5413   dying[player] = 1;
5414   flash = 1;
5415   playsound(SND_DIE1 + (rand() % 2), 3, 1);
5416 
5417 
5418   /* Kill any penguins we were carrying: */
5419 
5420   for (i = 0; i < MAX_PENGUINOIDS; i++)
5421     {
5422       if (penguinoids[player][i].alive == 1)
5423 	{
5424 	  if (penguinoids[player][i].mode == PENG_MODE_SAVED)
5425 	    penguinoids[player][i].alive = 0;
5426 	}
5427     }
5428 }
5429 
5430 
5431 /* Add some score: */
5432 
add_score(int add)5433 void add_score(int add)
5434 {
5435   score[player] = score[player] + add;
5436 
5437   if ((score[player] % 10000) < ((score[player] - add) % 10000))
5438     {
5439       lives[player]++;
5440       bombs[player]++;
5441 
5442       oneup_effect = 32;
5443       oneup_effect_counter = 3;
5444 
5445       playsound(SND_ONEUP, 1, 1);
5446     }
5447 
5448   if (score[player] > highscore)
5449     highscore = score[player];
5450 }
5451 
5452 
5453 /* Detonate a smart bomb: */
5454 
smartbomb(void)5455 void smartbomb(void)
5456 {
5457   int i, tmp_x;
5458 
5459   if (bombs[player] > 0)
5460     {
5461       /* Remove a bomb: */
5462 
5463       bombs[player]--;
5464 
5465 
5466       /* Kill all visible aliens! */
5467 
5468       for (i = 0; i < MAX_ALIENS; i++)
5469 	{
5470 	  if (aliens[player][i].alive == 1)
5471 	    {
5472 	      /* Relative position? */
5473 
5474 	      tmp_x = aliens[player][i].x - (x[player] -
5475 				     scroll[player]);
5476 
5477 	      while (tmp_x < 0)
5478 		tmp_x = tmp_x + (LAND_WIDTH * 32);
5479 
5480 	      while (tmp_x >= (LAND_WIDTH * 32))
5481 		tmp_x = tmp_x - (LAND_WIDTH * 32);
5482 
5483 
5484 	      /* Is it visible (on screen)? */
5485 
5486 	      if (tmp_x >= -32 && tmp_x <= 672)
5487 		{
5488 		  /* Kill the alien: */
5489 
5490 		  kill_alien(i);
5491 		}
5492 	    }
5493 	}
5494 
5495 
5496       /* Kill all visible bullets! */
5497 
5498       for (i = 0; i < MAX_BULLETS; i++)
5499 	{
5500 	  if (bullets[i].alive == 1)
5501 	    {
5502 	      /* Relative position? */
5503 
5504 	      tmp_x = bullets[i].x - (x[player] -
5505 				      scroll[player]);
5506 
5507 	      while (tmp_x >= (LAND_WIDTH * 32))
5508 		tmp_x = tmp_x - (LAND_WIDTH * 32);
5509 
5510 
5511 	      /* Is it visible (on screen)? */
5512 
5513 	      if (tmp_x >= -64 && tmp_x <= 672)
5514 		{
5515 		  /* Kill the alien: */
5516 
5517 		  bullets[i].alive = 0;
5518 		}
5519 	    }
5520 	}
5521 
5522 
5523       /* Noise and flash: */
5524 
5525       playsound(SND_SMARTBOMB, 1, 1);
5526 
5527       flash = 2;
5528     }
5529 }
5530 
5531 
5532 /* Usage display: */
5533 
usage(int err)5534 void usage(int err)
5535 {
5536   FILE * fi;
5537 
5538   if (err == 0)
5539     fi = stdout;
5540   else
5541     fi = stderr;
5542 
5543   fprintf(fi, "\n"
5544 	  "Usage: defendguin [--disable-sound] [--fullscreen] |\n"
5545 	  "       [--help | --copying | --usage | --version]\n"
5546 	  "\n"
5547 	  "  --disable-sound    Do not play music/sounds.\n"
5548 	  "                     (Also '--nosound' and '-q')\n"
5549 	  "  --fullscreen       Play fullscreen instead of windowed.\n"
5550 	  "                     (Also '-f')\n"
5551 	  "\n"
5552 	  "  --help             Display game help.  (Also '-h')\n"
5553 	  "  --usage            Display this usage info.  (Also '-u')\n"
5554 	  "  --copying          Display copying license (GPL)  (Also '-c')\n"
5555 	  "  --version          Display version (also '-v')\n"
5556 	  "\n");
5557 
5558   exit(err);
5559 }
5560 
5561 
5562 /* Pause screen: */
5563 
pause_screen(void)5564 void pause_screen(void)
5565 {
5566   SDL_Event event;
5567   SDL_Surface * old_screen;
5568   int done, mode, frame, x, y, xm, ym, a, r;
5569   Uint32 last_time;
5570   SDL_Rect src, dest;
5571 
5572 
5573   /* Create backup of current display: */
5574 
5575   old_screen = SDL_DisplayFormat(screen);
5576 
5577 
5578   /* Erase screen: */
5579 
5580   SDL_FillRect(screen, NULL,
5581 	       SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
5582 
5583 
5584   /* Stop playing music: */
5585 
5586 #ifndef NOSOUND
5587   if (use_sound == 1)
5588     Mix_PauseMusic();
5589 #endif /* #ifndef NOSOUND */
5590 
5591 
5592   /* --- Pause screen loop: --- */
5593 
5594   done = 0;
5595   frame = 0;
5596   mode = rand() % 4;
5597 
5598   x = (rand() % (640 - 32));
5599   y = (rand() % (480 - 32));
5600   xm = (rand() % 20) - 10;
5601   ym = (rand() % 20) - 10;
5602 
5603   do
5604     {
5605       last_time = SDL_GetTicks();
5606 
5607 
5608       /* Check for keypresses: */
5609 
5610       while (SDL_PollEvent(&event))
5611 	{
5612 	  if (event.type == SDL_KEYDOWN)
5613 	    done = 1;
5614 
5615 	  if (event.type == SDL_JOYBUTTONDOWN &&
5616 	      (num_joysticks < 2 || event.jbutton.which == player))
5617 	    {
5618 	      done = 1;
5619 	    }
5620 	}
5621 
5622 
5623       /* Draw screen: */
5624 
5625       frame++;
5626 
5627 
5628       if (mode == 0)
5629 	{
5630 	  for (y = (frame % 2); y < 480; y = y + 2)
5631 	    {
5632 	      dest.x = (my_cos[(y * 2) % 32] * (my_cos[frame % 32] * 10));
5633 	      dest.y = y + (my_cos[(y + frame) % 32] * 2);
5634 	      dest.w = 640;
5635 	      dest.h = 1;
5636 
5637 	      src.x = 0;
5638 	      src.y = y;
5639 	      src.w = 640;
5640 	      src.h = 1;
5641 
5642 	      SDL_BlitSurface(old_screen, &src, screen, &dest);
5643 	    }
5644 	}
5645       else if (mode == 1)
5646 	{
5647 	  for (r = 0; r < 240; r = r + 5)
5648 	    {
5649 	      for (a = 0; a < 360; a = a + 2)
5650 		{
5651 		  src.x = 320 + cos(M_PI * a / 180) * r;
5652 		  src.y = 240 - sin(M_PI * a / 180) * r;
5653 		  src.w = 8;
5654 		  src.h = 8;
5655 
5656 		  dest.x = 320 + cos(M_PI * (a + (frame * 5)) / 180) * r;
5657 		  dest.y = 240 - sin(M_PI * (a + (frame * 5)) / 180) * r;
5658 		  dest.w = 8;
5659 		  dest.h = 8;
5660 
5661 		  SDL_BlitSurface(old_screen, &src, screen, &dest);
5662 		}
5663 	    }
5664 	}
5665       else if (mode == 2)
5666 	{
5667 	  for (r = 0; r < 240; r = r + 10)
5668 	    {
5669 	      for (a = 0; a < 360; a = a + 5)
5670 		{
5671 		  src.x = 320 + cos(M_PI * a / 180) * r;
5672 		  src.y = 240 - sin(M_PI * a / 180) * r;
5673 		  src.w = 10;
5674 		  src.h = 10;
5675 
5676 		  dest.x = 320 + cos(M_PI * (a + ((frame % 3600) * r / 100)) /
5677 				     180) * r;
5678 		  dest.y = 240 - sin(M_PI * (a + ((frame % 3600) * r / 100)) /
5679 				     180) * r;
5680 		  dest.w = 10;
5681 		  dest.h = 10;
5682 
5683 		  SDL_BlitSurface(old_screen, &src, screen, &dest);
5684 		}
5685 	    }
5686 	}
5687       else if (mode == 3)
5688 	{
5689 	  SDL_FillRect(screen, NULL,
5690 		       SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
5691 
5692 	  x = x + xm;
5693 	  y = y + ym;
5694 
5695 	  if (x <= 0)
5696 	    {
5697 	      x = 0;
5698 	      xm = rand() % 10;
5699 	    }
5700  	  else if (x >= 640 - 128)
5701 	    {
5702 	      x = 640 - 128;
5703 	      xm = -(rand() % 10);
5704 	    }
5705 
5706 	  if (y <= 0)
5707 	    {
5708 	      y = 0;
5709 	      ym = rand() % 10;
5710 	    }
5711  	  else if (y >= 480 - 128)
5712 	    {
5713 	      y = 480 - 128;
5714 	      ym = -(rand() % 10);
5715 	    }
5716 
5717 	  src.x = x;
5718 	  src.y = y;
5719 	  src.w = 128;
5720 	  src.h = 128;
5721 
5722 	  SDL_BlitSurface(old_screen, &src, screen, &src);
5723 	  SDL_BlitSurface(images[IMG_CIRCLE], NULL, screen, &src);
5724 	}
5725 
5726 
5727       SDL_Flip(screen);
5728 
5729 
5730       /* Pause til next frame: */
5731 
5732       if (SDL_GetTicks() < last_time + 60)
5733 	SDL_Delay(last_time + 60 - SDL_GetTicks());
5734     }
5735   while (!done);
5736 
5737 
5738   /* Continue playing music: */
5739 
5740 #ifndef NOSOUND
5741   if (use_sound == 1)
5742     {
5743       Mix_ResumeMusic();
5744       Mix_VolumeMusic(vol_music * (MIX_MAX_VOLUME / 5));
5745     }
5746 #endif /* #ifndef NOSOUND */
5747 }
5748 
5749 
5750 /* Write text on the option screen: */
5751 
write_text(int x,int y,char * str)5752 void write_text(int x, int y, char * str)
5753 {
5754   int i, c;
5755   SDL_Rect src, dest;
5756 
5757   for (i = 0; i < strlen(str); i++)
5758     {
5759       c = -1;
5760 
5761       if (str[i] >= '0' && str[i] <= '9')
5762 	c = str[i] - '0';
5763       else if (str[i] >= 'A' && str[i] <= 'Z')
5764 	c = str[i] - 'A' + 10;
5765       else if (str[i] >= 'a' && str[i] <= 'z')
5766 	c = str[i] - 'a' + 36;
5767       else if (str[i] == '#')
5768 	c = 62;
5769       else if (str[i] == '=')
5770 	c = 63;
5771       else if (str[i] == '_')
5772 	c = -2;
5773       else if (str[i] == '-')
5774 	c = -3;
5775 
5776       if (c >= 0)
5777 	{
5778 	  src.x = c * 8;
5779 	  src.y = 0;
5780 	  src.w = 8;
5781 	  src.h = 8;
5782 
5783 	  dest.x = (x + i) * 8;
5784 	  dest.y = y * 10;
5785 	  dest.w = 8;
5786 	  dest.h = 8;
5787 
5788 	  SDL_BlitSurface(images[IMG_OPTION_TEXT], &src,
5789 			  screen, &dest);
5790 	}
5791       else if (c == -2 || c == -3)
5792 	{
5793 	  dest.x = (x + i) * 8;
5794 
5795 	  if (c == -2)
5796 	    dest.y = y * 10 + 7;
5797 	  else if (c == -3)
5798 	    dest.y = y * 10 + 3;
5799 
5800 	  dest.w = 8;
5801 	  dest.h = 1;
5802 
5803 	  SDL_FillRect(screen, &dest,
5804 		       SDL_MapRGB(screen->format, 0xCC, 0xCC, 0xCC));
5805 	}
5806     }
5807 
5808   SDL_UpdateRect(screen, x * 8, y * 10, strlen(str) * 8, 8);
5809 }
5810 
5811 
5812 /* Write text, inverted: */
5813 
write_text_inv(int x,int y,char * str)5814 void write_text_inv(int x, int y, char * str)
5815 {
5816   SDL_Rect dest;
5817 
5818   write_text(x, y, str);
5819 
5820   dest.x = x * 8;
5821   dest.y = y * 10 - 1;
5822   dest.w = strlen(str) * 8;
5823   dest.h = 1;
5824 
5825   SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 128, 128, 128));
5826 
5827   dest.x = x * 8;
5828   dest.y = y * 10 + 8;
5829   dest.w = strlen(str) * 8;
5830   dest.h = 1;
5831 
5832   SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 128, 128, 128));
5833 }
5834 
5835 
5836 /* Write text, horizontally centered... */
5837 
write_centered_text(int y,char * str)5838 void write_centered_text(int y, char * str)
5839 {
5840   write_text(40 - (strlen(str) / 2), y, str);
5841 }
5842 
5843 
5844 /* Write numbers on the option screen: */
5845 
write_num(int x,int y,int v)5846 void write_num(int x, int y, int v)
5847 {
5848   char str[24];
5849 
5850   sprintf(str, "%d", v);
5851   write_text(x, y, str);
5852 }
5853 
5854 
5855 /* Return the value of a particular line's option: */
5856 
option_value(int opt_line)5857 int option_value(int opt_line)
5858 {
5859   if (opt_line == 3)
5860     return (vol_effects);
5861   else if (opt_line == 4)
5862     return (vol_music);
5863   else if (opt_line == 5)
5864     return (joy_fire);
5865   else if (opt_line == 6)
5866     return (joy_bomb);
5867   else if (opt_line == 7)
5868     return (joy_x);
5869   else if (opt_line == 8)
5870     return (joy_y);
5871   else
5872     return (0);
5873 }
5874 
5875 
5876 /* Load options from the options file */
5877 
load_options(void)5878 void load_options(void)
5879 {
5880   FILE * fi;
5881   char fname[512], str[128];
5882 
5883   vol_effects = 5;
5884   vol_music = 5;
5885 
5886   if (getenv("HOME") != NULL)
5887     {
5888       snprintf(fname, sizeof(fname), "%s/.defendguinrc", getenv("HOME"));
5889 
5890       fi = fopen(fname, "r");
5891 
5892       if (fi != NULL)
5893         {
5894 	  do
5895 	    {
5896 	      fgets(str, sizeof(str), fi);
5897 	      str[strlen(str) - 1] = '\0';
5898 
5899 	      if (strchr(str, '=') != NULL)
5900 	        {
5901 	          if (strstr(str, "CONFIG_EFFECTS_VOLUME") != NULL)
5902 		    sscanf(strchr(str, '=') + 1, "%d", &vol_effects);
5903 	          else if (strstr(str, "CONFIG_MUSIC_VOLUME") != NULL)
5904 		    sscanf(strchr(str, '=') + 1, "%d", &vol_music);
5905 	          else if (strstr(str, "CONFIG_JOY_FIRE") != NULL)
5906 		    sscanf(strchr(str, '=') + 1, "%d", &joy_fire);
5907 	          else if (strstr(str, "CONFIG_JOY_BOMB") != NULL)
5908 		    sscanf(strchr(str, '=') + 1, "%d", &joy_bomb);
5909 	          else if (strstr(str, "CONFIG_JOY_X") != NULL)
5910 		    sscanf(strchr(str, '=') + 1, "%d", &joy_x);
5911 	          else if (strstr(str, "CONFIG_JOY_Y") != NULL)
5912 		    sscanf(strchr(str, '=') + 1, "%d", &joy_y);
5913 	          else if (strstr(str, "SCORE_HIGH") != NULL)
5914 		    sscanf(strchr(str, '=') + 1, "%d", &highscore);
5915 	          else if (strstr(str, "SCORE_LAST_1") != NULL)
5916 		    sscanf(strchr(str, '=') + 1, "%d", &(score[0]));
5917 	          else if (strstr(str, "SCORE_LAST_2") != NULL)
5918 		    sscanf(strchr(str, '=') + 1, "%d", &(score[1]));
5919 	          else if (strstr(str, "LEVEL_LAST_1") != NULL)
5920 		    sscanf(strchr(str, '=') + 1, "%d", &(level[0]));
5921 	          else if (strstr(str, "LEVEL_LAST_2") != NULL)
5922 		    sscanf(strchr(str, '=') + 1, "%d", &(level[1]));
5923 		}
5924 	    }
5925 	  while (!feof(fi));
5926 
5927 	  fclose(fi);
5928 
5929 	  if (vol_effects < 0)
5930 	    vol_effects = 0;
5931 	  else if (vol_effects > 5)
5932 	    vol_effects = 5;
5933 
5934 	  if (vol_music < 0)
5935 	    vol_music = 0;
5936 	  else if (vol_music > 5)
5937 	    vol_music = 5;
5938         }
5939     }
5940 }
5941 
5942 
5943 /* Save options to options file: */
5944 
save_options(void)5945 void save_options(void)
5946 {
5947   FILE * fi;
5948   char fname[512];
5949 
5950   if (getenv("HOME") != NULL)
5951     {
5952       snprintf(fname, sizeof(fname), "%s/.defendguinrc", getenv("HOME"));
5953 
5954       fi = fopen(fname, "w");
5955 
5956       if (fi != NULL)
5957         {
5958 	  fprintf(fi, "# Defendguin Options File\n\n");
5959 	  fprintf(fi, "CONFIG_EFFECTS_VOLUME = %d\n", vol_effects);
5960 	  fprintf(fi, "CONFIG_MUSIC_VOLUME = %d\n", vol_music);
5961 	  fprintf(fi, "CONFIG_JOY_FIRE = %d\n", joy_fire);
5962 	  fprintf(fi, "CONFIG_JOY_BOMB = %d\n", joy_bomb);
5963 	  fprintf(fi, "CONFIG_JOY_X = %d\n", joy_x);
5964 	  fprintf(fi, "CONFIG_JOY_Y = %d\n", joy_y);
5965 	  fprintf(fi, "SCORE_LAST_1 = %d\n", score[0]);
5966 	  fprintf(fi, "SCORE_LAST_2 = %d\n", score[1]);
5967 	  fprintf(fi, "LEVEL_LAST_1 = %d\n", level[0]);
5968 	  fprintf(fi, "LEVEL_LAST_2 = %d\n", level[1]);
5969 	  fprintf(fi, "SCORE_HIGH = %d\n", highscore);
5970 
5971 	  fclose(fi);
5972         }
5973     }
5974 }
5975