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