A brandnew MENU!
[supertux.git] / src / gameloop.c
1 /*
2   gameloop.c
3   
4   Super Tux - Game Loop!
5   
6   by Bill Kendrick
7   bill@newbreedsoftware.com
8   http://www.newbreedsoftware.com/supertux/
9   
10   April 11, 2000 - December 9, 2003
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <SDL.h>
19
20 #ifdef LINUX
21 #include <pwd.h>
22 #include <sys/types.h>
23 #include <ctype.h>
24 #endif
25
26 #include "defines.h"
27 #include "globals.h"
28 #include "gameloop.h"
29 #include "screen.h"
30 #include "sound.h"
31 #include "setup.h"
32 #include "high_scores.h"
33 #include "menu.h"
34
35
36 /* Sound files: */
37
38 enum {
39   SND_JUMP,
40   SND_BIGJUMP,
41   SND_SKID,
42   SND_DISTRO,
43   SND_HERRING,
44   SND_BRICK,
45   SND_HURT,
46   SND_SQUISH,
47   SND_FALL,
48   SND_RICOCHET,
49   SND_BUMP_UPGRADE,
50   SND_UPGRADE,
51   SND_EXCELLENT,
52   SND_COFFEE,
53   SND_SHOOT,
54   SND_LIFEUP
55 };
56
57
58 char * soundfilenames[NUM_SOUNDS] = {
59                                       DATA_PREFIX "/sounds/jump.wav",
60                                       DATA_PREFIX "/sounds/bigjump.wav",
61                                       DATA_PREFIX "/sounds/skid.wav",
62                                       DATA_PREFIX "/sounds/distro.wav",
63                                       DATA_PREFIX "/sounds/herring.wav",
64                                       DATA_PREFIX "/sounds/brick.wav",
65                                       DATA_PREFIX "/sounds/hurt.wav",
66                                       DATA_PREFIX "/sounds/squish.wav",
67                                       DATA_PREFIX "/sounds/fall.wav",
68                                       DATA_PREFIX "/sounds/ricochet.wav",
69                                       DATA_PREFIX "/sounds/bump-upgrade.wav",
70                                       DATA_PREFIX "/sounds/upgrade.wav",
71                                       DATA_PREFIX "/sounds/excellent.wav",
72                                       DATA_PREFIX "/sounds/coffee.wav",
73                                       DATA_PREFIX "/sounds/shoot.wav",
74                                       DATA_PREFIX "/sounds/lifeup.wav"
75                                     };
76
77
78 /* Local variables: */
79
80 int score, highscore, distros, level, lives, scroll_x, next_level, game_pause,
81 done, quit, tux_dir, tux_size, tux_duck, tux_x, tux_xm, tux_y, tux_ym,
82 tux_dying, tux_safe, jumping, jump_counter, frame, score_multiplier,
83 tux_frame_main, tux_frame, tux_got_coffee, tux_skidding,
84 super_bkgd_time, time_left, tux_invincible_time, endpos,
85 counting_distros, distro_counter;
86 int bkgd_red, bkgd_green, bkgd_blue, level_width;
87 int left, right, up, down, fire, old_fire;
88 SDL_Surface * img_brick[2], * img_solid[4], * img_distro[4],
89 * img_waves[3], * img_water, * img_pole, * img_poletop, * img_flag[2];
90 SDL_Surface * img_bkgd[2][4];
91 SDL_Surface * img_golden_herring;
92 SDL_Surface * img_bsod_left[4], * img_bsod_right[4],
93 * img_laptop_left[3], * img_laptop_right[3],
94 * img_money_left[2], * img_money_right[2];
95 SDL_Surface * img_bsod_squished_left, * img_bsod_squished_right,
96 * img_bsod_falling_left, * img_bsod_falling_right,
97 * img_laptop_flat_left, * img_laptop_flat_right,
98 * img_laptop_falling_left, * img_laptop_falling_right;
99 SDL_Surface * img_box_full, * img_box_empty, * img_mints, * img_coffee,
100 * img_super_bkgd, * img_bullet, * img_red_glow;
101 SDL_Surface * img_cloud[2][4];
102 SDL_Surface * tux_right[3], * tux_left[3],
103 * bigtux_right[3], * bigtux_left[3],
104 * bigtux_right_jump, * bigtux_left_jump,
105 * cape_right[2], * cape_left[2],
106 * bigcape_right[2], * bigcape_left[2],
107 * ducktux_right, * ducktux_left,
108 * skidtux_right, * skidtux_left;
109 SDL_Event event;
110 SDL_Rect src, dest;
111 SDLKey key;
112 unsigned char * tiles[15];
113 bouncy_distro_type bouncy_distros[NUM_BOUNCY_DISTROS];
114 broken_brick_type broken_bricks[NUM_BROKEN_BRICKS];
115 bouncy_brick_type bouncy_bricks[NUM_BOUNCY_BRICKS];
116 bad_guy_type bad_guys[NUM_BAD_GUYS];
117 floating_score_type floating_scores[NUM_FLOATING_SCORES];
118 upgrade_type upgrades[NUM_UPGRADES];
119 bullet_type bullets[NUM_BULLETS];
120 char song_title[20];
121 char levelname[20];
122 char leveltheme[20];
123 char str[10];
124
125 /* Local function prototypes: */
126
127 void initgame(void);
128 void loadlevel(void);
129 void loadlevelgfx(void);
130 void loadlevelsong(void);
131 void unloadlevelgfx(void);
132 void unloadlevelsong(void);
133 void loadshared(void);
134 void unloadshared(void);
135 void drawshape(int x, int y, unsigned char c);
136 unsigned char shape(int x, int y, int sx);
137 int issolid(int x, int y, int sx);
138 int isbrick(int x, int y, int sx);
139 int isice(int x, int y, int sx);
140 int isfullbox(int x, int y, int sx);
141 void change(int x, int y, int sx, unsigned char c);
142 void trybreakbrick(int x, int y, int sx);
143 void bumpbrick(int x, int y, int sx);
144 void tryemptybox(int x, int y, int sx);
145 void trygrabdistro(int x, int y, int sx, int bounciness);
146 void add_bouncy_distro(int x, int y);
147 void add_broken_brick(int x, int y);
148 void add_broken_brick_piece(int x, int y, int xm, int ym);
149 void add_bouncy_brick(int x, int y);
150 void add_bad_guy(int x, int y, int kind);
151 void add_score(int x, int y, int s);
152 void trybumpbadguy(int x, int y, int sx);
153 void add_upgrade(int x, int y, int kind);
154 void killtux(int mode);
155 void add_bullet(int x, int y, int dir, int xm);
156 void drawendscreen(void);
157 void drawresultscreen(void);
158
159 /* --- GAME EVENT! --- */
160
161 void game_event(void)
162 {
163
164   while (SDL_PollEvent(&event))
165     {
166
167       if (event.type == SDL_QUIT)
168         {
169           /* Quit event - quit: */
170
171           quit = 1;
172         }
173       else if (event.type == SDL_KEYDOWN)
174         {
175           /* A keypress! */
176
177           key = event.key.keysym.sym;
178
179           if (key == SDLK_ESCAPE)
180             {
181               /* Escape: Open/Close the menu: */
182               if(!game_pause)
183                 {
184                   if(show_menu)
185                     show_menu = 0;
186                   else
187                     show_menu = 1;
188                 }
189             }
190           else if (key == SDLK_RIGHT)
191             {
192               right = DOWN;
193             }
194           else if (key == SDLK_LEFT)
195             {
196               left = DOWN;
197             }
198           else if (key == SDLK_UP)
199             {
200               up = DOWN;
201             }
202           else if (key == SDLK_DOWN)
203             {
204               down = DOWN;
205             }
206           else if (key == SDLK_LCTRL)
207             {
208               fire = DOWN;
209             }
210         }
211       else if (event.type == SDL_KEYUP)
212         {
213           /* A keyrelease! */
214
215           key = event.key.keysym.sym;
216
217           /* Check for menu-events, if the menu is shown */
218           if(show_menu)
219             menu_event(key);
220
221           if (key == SDLK_RIGHT)
222             {
223               right = UP;
224             }
225           else if (key == SDLK_LEFT)
226             {
227               left = UP;
228             }
229           else if (key == SDLK_UP)
230             {
231               up = UP;
232             }
233           else if (key == SDLK_DOWN)
234             {
235               down = UP;
236             }
237           else if (key == SDLK_LCTRL)
238             {
239               fire = UP;
240             }
241           else if (key == SDLK_p)
242             {
243               if(!show_menu)
244                 {
245                   if(game_pause)
246                     game_pause = 0;
247                   else
248                     game_pause = 1;
249                 }
250             }
251           else if (key == SDLK_TAB)
252             {
253               tux_size = !tux_size;
254             }
255           else if (key == SDLK_END)
256             {
257               distros += 50;
258             }
259           else if (key == SDLK_SPACE)
260             {
261               next_level = 1;
262             }
263         }
264 #ifdef JOY_YES
265       else if (event.type == SDL_JOYAXISMOTION)
266         {
267           if (event.jaxis.axis == JOY_X)
268             {
269               if (event.jaxis.value < -256)
270                 left = DOWN;
271               else
272                 left = UP;
273
274               if (event.jaxis.value > 256)
275                 right = DOWN;
276               else
277                 right = UP;
278             }
279           else if (event.jaxis.axis == JOY_Y)
280             {
281               if (event.jaxis.value > 256)
282                 down = DOWN;
283               else
284                 down = UP;
285
286               /* Handle joystick for the menu */
287               if(show_menu)
288                 {
289                   if(down == DOWN)
290                     menuaction = MN_DOWN;
291                   else
292                     menuaction = MN_UP;
293                 }
294             }
295         }
296       else if (event.type == SDL_JOYBUTTONDOWN)
297         {
298           if (event.jbutton.button == JOY_A)
299             up = DOWN;
300           else if (event.jbutton.button == JOY_B)
301             fire = DOWN;
302         }
303       else if (event.type == SDL_JOYBUTTONUP)
304         {
305           if (event.jbutton.button == JOY_A)
306             up = UP;
307           else if (event.jbutton.button == JOY_B)
308             fire = UP;
309
310           if(show_menu)
311             menuaction = MN_HIT;
312
313         }
314 #endif
315
316     }
317
318 }
319
320 /* --- GAME ACTION! --- */
321
322 int game_action(void)
323 {
324   int i,j;
325
326   /* --- HANDLE TUX! --- */
327
328   /* Handle key and joystick state: */
329
330   if (!(tux_dying || next_level))
331     {
332       if (right == DOWN && left == UP)
333         {
334           if (jumping == NO)
335             {
336               if (tux_xm < -SKID_XM && !tux_skidding &&
337                   tux_dir == LEFT)
338                 {
339                   tux_skidding = SKID_TIME;
340
341                   play_sound(sounds[SND_SKID]);
342
343                 }
344               tux_dir = RIGHT;
345             }
346
347           if (tux_xm < 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
348               !tux_skidding)
349             {
350               tux_xm = 0;
351             }
352
353           if (!tux_duck)
354             {
355               if (tux_dir == RIGHT)
356                 {
357                   /* Facing the direction we're jumping?  Go full-speed: */
358
359                   if (fire == UP)
360                     {
361                       tux_xm = tux_xm + WALK_SPEED;
362
363                       if (tux_xm > MAX_WALK_XM)
364                         tux_xm = MAX_WALK_XM;
365                     }
366                   else if (fire == DOWN)
367                     {
368                       tux_xm = tux_xm + RUN_SPEED;
369
370                       if (tux_xm > MAX_RUN_XM)
371                         tux_xm = MAX_RUN_XM;
372                     }
373                 }
374               else
375                 {
376                   /* Not facing the direction we're jumping?
377                   Go half-speed: */
378
379                   tux_xm = tux_xm + WALK_SPEED / 2;
380
381                   if (tux_xm > MAX_WALK_XM / 2)
382                     tux_xm = MAX_WALK_XM / 2;
383                 }
384             }
385         }
386       else if (left == DOWN && right == UP)
387         {
388           if (jumping == NO)
389             {
390               if (tux_xm > SKID_XM && !tux_skidding &&
391                   tux_dir == RIGHT)
392                 {
393                   tux_skidding = SKID_TIME;
394                   play_sound(sounds[SND_SKID]);
395                 }
396               tux_dir = LEFT;
397             }
398
399           if (tux_xm > 0 && !isice(tux_x, tux_y + 32, scroll_x) &&
400               !tux_skidding)
401             {
402               tux_xm = 0;
403             }
404
405           if (!tux_duck)
406             {
407               if (tux_dir == LEFT)
408                 {
409                   /* Facing the direction we're jumping?  Go full-speed: */
410
411                   if (fire == UP)
412                     {
413                       tux_xm = tux_xm - WALK_SPEED;
414
415                       if (tux_xm < -MAX_WALK_XM)
416                         tux_xm = -MAX_WALK_XM;
417                     }
418                   else if (fire == DOWN)
419                     {
420                       tux_xm = tux_xm - RUN_SPEED;
421
422                       if (tux_xm < -MAX_RUN_XM)
423                         tux_xm = -MAX_RUN_XM;
424                     }
425                 }
426               else
427                 {
428                   /* Not facing the direction we're jumping?
429                   Go half-speed: */
430
431                   tux_xm = tux_xm - WALK_SPEED / 2;
432
433                   if (tux_xm < -MAX_WALK_XM / 2)
434                     tux_xm = -MAX_WALK_XM / 2;
435                 }
436             }
437         }
438
439
440       /* End of level? */
441
442       if (tux_x >= endpos && endpos != 0)
443         {
444           next_level = 1;
445         }
446
447
448       /* Jump/jumping? */
449
450       if (up == DOWN)
451         {
452           if (jump_counter == 0)
453             {
454               /* Taking off? */
455
456               if (!issolid(tux_x, tux_y + 32, scroll_x) ||
457                   tux_ym != 0)
458                 {
459                   /* If they're not on the ground, or are currently moving
460                   vertically, don't jump! */
461
462                   jump_counter = MAX_JUMP_COUNT;
463                 }
464               else
465                 {
466                   /* Make sure we're not standing back up into a solid! */
467
468                   if (tux_size == SMALL || tux_duck == NO ||
469                       !issolid(tux_x, tux_y, scroll_x))
470                     {
471                       jumping = YES;
472
473                       if (tux_size == SMALL)
474                         play_sound(sounds[SND_JUMP]);
475                       else
476                         play_sound(sounds[SND_BIGJUMP]);
477                     }
478                 }
479             }
480
481
482           /* Keep jumping for a while: */
483
484           if (jump_counter < MAX_JUMP_COUNT)
485             {
486               tux_ym = tux_ym - JUMP_SPEED;
487               jump_counter++;
488             }
489         }
490       else
491         jump_counter = 0;
492
493
494       /* Shoot! */
495
496       if (fire == DOWN && old_fire == UP && tux_got_coffee)
497         {
498           add_bullet(tux_x + scroll_x, tux_y, tux_dir, tux_xm);
499         }
500
501
502       /* Duck! */
503
504       if (down == DOWN)
505         {
506           if (tux_size == BIG)
507             tux_duck = YES;
508         }
509       else
510         {
511           if (tux_size == BIG && tux_duck == YES)
512             {
513               /* Make sure we're not standing back up into a solid! */
514
515               if (!issolid(tux_x, tux_y - 32, scroll_x))
516                 tux_duck = NO;
517             }
518           else
519             tux_duck = NO;
520         }
521     } /* (tux_dying || next_level) */
522   else
523     {
524       /* Tux either died, or reached the end of a level! */
525
526
527       if (playing_music())
528         halt_music();
529
530
531       if (next_level)
532         {
533           /* End of a level! */
534           level++;
535           next_level = 0;
536           drawresultscreen();
537         }
538       else
539         {
540
541           tux_ym = tux_ym + GRAVITY;
542
543
544
545           /* He died :^( */
546
547           lives--;
548
549           /* No more lives!? */
550
551           if (lives < 0)
552             {
553               drawendscreen();
554
555               if (score > highscore)
556                 save_hs(score);
557
558               return(0);
559             } /* if (lives < 0) */
560         }
561
562       /* Either way, (re-)load the (next) level... */
563
564       loadlevel();
565       unloadlevelgfx();
566       loadlevelgfx();
567       unloadlevelsong();
568       loadlevelsong();
569     }
570
571   /* Move tux: */
572
573   tux_x = tux_x + tux_xm;
574   tux_y = tux_y + tux_ym;
575
576
577   /* Keep tux in bounds: */
578
579   if (tux_x < 0)
580     tux_x = 0;
581   else if (tux_x > 320 && scroll_x < ((level_width * 32) - 640))
582     {
583       /* Scroll the screen in past center: */
584
585       scroll_x = scroll_x + (tux_x - 320);
586       tux_x = 320;
587
588       if (scroll_x > ((level_width * 32) - 640))
589         scroll_x = ((level_width * 32) - 640);
590     }
591   else if (tux_x > 608)
592     {
593       /* ... unless there's no more to scroll! */
594
595       tux_x = 608;
596     }
597
598
599   /* Land: */
600
601   if (!tux_dying)
602     {
603       if (issolid(tux_x, tux_y + 31, scroll_x) &&
604           !issolid(tux_x - tux_xm, tux_y + 31, scroll_x))
605         {
606           while (issolid(tux_x, tux_y + 31, scroll_x))
607             {
608               if (tux_xm < 0)
609                 tux_x++;
610               else if (tux_xm > 0)
611                 tux_x--;
612             }
613
614           tux_xm = 0;
615         }
616
617       if (issolid(tux_x, tux_y, scroll_x) &&
618           !issolid(tux_x - tux_xm, tux_y, scroll_x))
619         {
620           while (issolid(tux_x, tux_y, scroll_x))
621             {
622               if (tux_xm < 0)
623                 tux_x++;
624               else if (tux_xm > 0)
625                 tux_x--;
626             }
627
628           tux_xm = 0;
629         }
630
631       if (issolid(tux_x, tux_y + 31, scroll_x))
632         {
633           /* Set down properly: */
634
635           while (issolid(tux_x, tux_y + 31, scroll_x))
636             {
637               if (tux_ym < 0)
638                 tux_y++;
639               else if (tux_ym > 0)
640                 tux_y--;
641             }
642
643
644           /* Reset score multiplier (for mutli-hits): */
645
646           if (tux_ym > 0)
647             score_multiplier = 1;
648
649
650           /* Stop jumping! */
651
652           tux_ym = 0;
653           jumping = NO;
654         }
655
656
657       /* Bump into things: */
658
659       if (issolid(tux_x, tux_y, scroll_x) ||
660           (tux_size == BIG && !tux_duck &&
661            (issolid(tux_x, tux_y - 32, scroll_x))))
662         {
663           if (!issolid(tux_x - tux_xm, tux_y, scroll_x) &&
664               (tux_size == SMALL || tux_duck ||
665                !issolid(tux_x - tux_xm, tux_y - 32, scroll_x)))
666             {
667               tux_x = tux_x - tux_xm;
668               tux_xm = 0;
669             }
670           else if (!issolid(tux_x, tux_y - tux_ym, scroll_x) &&
671                    (tux_size == SMALL || tux_duck ||
672                     !issolid(tux_x, tux_y - 32 - tux_ym, scroll_x)))
673             {
674               if (tux_ym <= 0)
675                 {
676                   /* Jumping up? */
677
678                   if (tux_size == BIG)
679                     {
680                       /* Break bricks and empty boxes: */
681
682                       if (!tux_duck)
683                         {
684                           if (isbrick(tux_x, tux_y - 32, scroll_x) ||
685                               isfullbox(tux_x, tux_y - 32, scroll_x))
686                             {
687                               trygrabdistro(tux_x, tux_y - 64, scroll_x,
688                                             BOUNCE);
689                               trybumpbadguy(tux_x, tux_y - 96, scroll_x);
690
691                               if (isfullbox(tux_x, tux_y - 32,
692                                             scroll_x))
693                                 {
694                                   bumpbrick(tux_x, tux_y - 32,
695                                             scroll_x);
696                                 }
697
698                               trybreakbrick(tux_x, tux_y - 32, scroll_x);
699                               tryemptybox(tux_x, tux_y - 32, scroll_x);
700                             }
701
702                           if (isbrick(tux_x + 31, tux_y - 32, scroll_x) ||
703                               isfullbox(tux_x + 31, tux_y - 32, scroll_x))
704                             {
705                               trygrabdistro(tux_x + 31,
706                                             tux_y - 64,
707                                             scroll_x,
708                                             BOUNCE);
709                               trybumpbadguy(tux_x + 31,
710                                             tux_y - 96,
711                                             scroll_x);
712
713                               if (isfullbox(tux_x + 31, tux_y - 32,
714                                             scroll_x))
715                                 {
716                                   bumpbrick(tux_x + 31, tux_y - 32,
717                                             scroll_x);
718                                 }
719
720                               trybreakbrick(tux_x + 31,
721                                             tux_y - 32,
722                                             scroll_x);
723                               tryemptybox(tux_x + 31,
724                                           tux_y - 32,
725                                           scroll_x);
726                             }
727                         }
728                       else /* ducking */
729                         {
730                           if (isbrick(tux_x, tux_y, scroll_x) ||
731                               isfullbox(tux_x, tux_y, scroll_x))
732                             {
733                               trygrabdistro(tux_x, tux_y - 32, scroll_x,
734                                             BOUNCE);
735                               trybumpbadguy(tux_x, tux_y - 64, scroll_x);
736                               if (isfullbox(tux_x, tux_y, scroll_x))
737                                 bumpbrick(tux_x, tux_y, scroll_x);
738                               trybreakbrick(tux_x, tux_y, scroll_x);
739                               tryemptybox(tux_x, tux_y, scroll_x);
740                             }
741
742                           if (isbrick(tux_x + 31, tux_y, scroll_x) ||
743                               isfullbox(tux_x + 31, tux_y, scroll_x))
744                             {
745                               trygrabdistro(tux_x + 31,
746                                             tux_y - 32,
747                                             scroll_x,
748                                             BOUNCE);
749                               trybumpbadguy(tux_x + 31,
750                                             tux_y - 64,
751                                             scroll_x);
752                               if (isfullbox(tux_x + 31, tux_y, scroll_x))
753                                 bumpbrick(tux_x + 31, tux_y, scroll_x);
754                               trybreakbrick(tux_x + 31, tux_y, scroll_x);
755                               tryemptybox(tux_x + 31, tux_y, scroll_x);
756                             }
757                         }
758                     }
759                   else
760                     {
761                       /* It's a brick and we're small, make the brick
762                          bounce, and grab any distros above it: */
763
764                       if (isbrick(tux_x, tux_y, scroll_x) ||
765                           isfullbox(tux_x, tux_y, scroll_x))
766                         {
767                           trygrabdistro(tux_x, tux_y - 32, scroll_x,
768                                         BOUNCE);
769                           trybumpbadguy(tux_x, tux_y - 64, scroll_x);
770                           bumpbrick(tux_x, tux_y, scroll_x);
771                           tryemptybox(tux_x, tux_y, scroll_x);
772                         }
773
774                       if (isbrick(tux_x + 31, tux_y, scroll_x) ||
775                           isfullbox(tux_x + 31, tux_y, scroll_x))
776                         {
777                           trygrabdistro(tux_x + 31, tux_y - 32, scroll_x,
778                                         BOUNCE);
779                           trybumpbadguy(tux_x + 31, tux_y - 64, scroll_x);
780                           bumpbrick(tux_x + 31, tux_y, scroll_x);
781                           tryemptybox(tux_x + 31, tux_y, scroll_x);
782                         }
783
784
785                       /* Get a distro from a brick? */
786
787                       if (shape(tux_x, tux_y, scroll_x) == 'x' ||
788                           shape(tux_x, tux_y, scroll_x) == 'y')
789                         {
790                           add_bouncy_distro(((tux_x + scroll_x + 1)
791                                              / 32) * 32,
792                                             (tux_y / 32) * 32);
793
794                           if (counting_distros == NO)
795                             {
796                               counting_distros = YES;
797                               distro_counter = 100;
798                             }
799
800                           if (distro_counter <= 0)
801                             change(tux_x, tux_y, scroll_x, 'a');
802
803                           play_sound(sounds[SND_DISTRO]);
804                           score = score + SCORE_DISTRO;
805                           distros++;
806                         }
807                       else if (shape(tux_x + 31, tux_y, scroll_x) == 'x' ||
808                                shape(tux_x + 31, tux_y, scroll_x) == 'y')
809                         {
810                           add_bouncy_distro(((tux_x + scroll_x + 1 + 31)
811                                              / 32) * 32,
812                                             (tux_y / 32) * 32);
813
814                           if (counting_distros == NO)
815                             {
816                               counting_distros = YES;
817                               distro_counter = 100;
818                             }
819
820                           if (distro_counter <= 0)
821                             change(tux_x + 31, tux_y, scroll_x, 'a');
822
823                           play_sound(sounds[SND_DISTRO]);
824                           score = score + SCORE_DISTRO;
825                           distros++;
826                         }
827                     }
828
829
830                   /* Bump head: */
831
832                   tux_y = (tux_y / 32) * 32 + 30;
833                 }
834               else
835                 {
836                   /* Land on feet: */
837
838                   tux_y = (tux_y / 32) * 32 - 32;
839                 }
840
841               tux_ym = 0;
842               jumping = NO;
843               jump_counter = MAX_JUMP_COUNT;
844             }
845         }
846     }
847
848
849   /* Grab distros: */
850
851   if (!tux_dying)
852     {
853       trygrabdistro(tux_x, tux_y, scroll_x, NO_BOUNCE);
854       trygrabdistro(tux_x + 31, tux_y, scroll_x, NO_BOUNCE);
855
856       if (tux_size == BIG && !tux_duck)
857         {
858           trygrabdistro(tux_x, tux_y - 32, scroll_x, NO_BOUNCE);
859           trygrabdistro(tux_x + 31, tux_y - 32, scroll_x, NO_BOUNCE);
860         }
861     }
862
863
864   /* Enough distros for a One-up? */
865
866   if (distros >= DISTROS_LIFEUP)
867     {
868       distros = distros - DISTROS_LIFEUP;
869       if(lives < MAX_LIVES)
870         lives++;
871       play_sound(sounds[SND_LIFEUP]); /*We want to hear the sound even, if MAX_LIVES is reached*/
872     }
873
874
875   /* Keep in-bounds, vertically: */
876
877   if (tux_y < 0)
878     tux_y = 0;
879   else if (tux_y > 480)
880     {
881       killtux(KILL);
882     }
883
884
885   /* Slow down horizontally: */
886
887   if (!tux_dying)
888     {
889       if (right == UP && left == UP)
890         {
891           if (isice(tux_x, tux_y + 32, scroll_x) ||
892               !issolid(tux_x, tux_y + 32, scroll_x))
893             {
894               /* Slowly on ice or in air: */
895
896               if (tux_xm > 0)
897                 tux_xm--;
898               else if (tux_xm < 0)
899                 tux_xm++;
900             }
901           else
902             {
903               /* Quickly, otherwise: */
904
905               tux_xm = tux_xm / 2;
906             }
907         }
908
909
910       /* Drop vertically: */
911
912       if (!issolid(tux_x, tux_y + 32, scroll_x))
913         {
914           tux_ym = tux_ym + GRAVITY;
915
916           if (tux_ym > MAX_YM)
917             tux_ym = MAX_YM;
918         }
919     }
920
921
922   if (tux_safe > 0)
923     tux_safe--;
924
925
926   /* ---- DONE HANDLING TUX! --- */
927
928
929   /* Handle bouncy distros: */
930
931   for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
932     {
933       if (bouncy_distros[i].alive)
934         {
935           bouncy_distros[i].y = bouncy_distros[i].y + bouncy_distros[i].ym;
936
937           bouncy_distros[i].ym++;
938
939           if (bouncy_distros[i].ym >= 0)
940             bouncy_distros[i].alive = NO;
941         }
942     }
943
944
945   /* Handle broken bricks: */
946
947   for (i = 0; i < NUM_BROKEN_BRICKS; i++)
948     {
949       if (broken_bricks[i].alive)
950         {
951           broken_bricks[i].x = broken_bricks[i].x + broken_bricks[i].xm;
952           broken_bricks[i].y = broken_bricks[i].y + broken_bricks[i].ym;
953
954           broken_bricks[i].ym++;
955
956           if (broken_bricks[i].ym >= 0)
957             broken_bricks[i].alive = NO;
958         }
959     }
960
961
962   /* Handle distro counting: */
963
964   if (counting_distros == YES)
965     {
966       distro_counter--;
967
968       if (distro_counter <= 0)
969         counting_distros = -1;
970     }
971
972
973   /* Handle bouncy bricks: */
974
975   for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
976     {
977       if (bouncy_bricks[i].alive)
978         {
979           bouncy_bricks[i].offset = (bouncy_bricks[i].offset +
980                                      bouncy_bricks[i].offset_m);
981
982           /* Go back down? */
983
984           if (bouncy_bricks[i].offset < -BOUNCY_BRICK_MAX_OFFSET)
985             bouncy_bricks[i].offset_m = BOUNCY_BRICK_SPEED;
986
987
988           /* Stop bouncing? */
989
990           if (bouncy_bricks[i].offset == 0)
991             bouncy_bricks[i].alive = NO;
992         }
993     }
994
995
996   /* Handle floating scores: */
997
998   for (i = 0; i < NUM_FLOATING_SCORES; i++)
999     {
1000       if (floating_scores[i].alive)
1001         {
1002           floating_scores[i].y = floating_scores[i].y - 2;
1003           floating_scores[i].timer--;
1004
1005           if (floating_scores[i].timer <= 0)
1006             floating_scores[i].alive = NO;
1007         }
1008     }
1009
1010
1011   /* Handle bullets: */
1012
1013   for (i = 0; i < NUM_BULLETS; i++)
1014     {
1015       if (bullets[i].alive)
1016         {
1017           bullets[i].x = bullets[i].x + bullets[i].xm;
1018           bullets[i].y = bullets[i].y + bullets[i].ym;
1019
1020           if (issolid(bullets[i].x, bullets[i].y, 0))
1021             {
1022               if (issolid(bullets[i].x, bullets[i].y - bullets[i].ym, 0))
1023                 bullets[i].alive = NO;
1024               else
1025                 {
1026                   if (bullets[i].ym >= 0)
1027                     {
1028                       bullets[i].y = (bullets[i].y / 32) * 32 - 8;
1029                     }
1030                   bullets[i].ym = -bullets[i].ym;
1031                 }
1032             }
1033
1034           bullets[i].ym = bullets[i].ym + GRAVITY;
1035
1036           if (bullets[i].x < scroll_x ||
1037               bullets[i].x > scroll_x + 640)
1038             {
1039               bullets[i].alive = NO;
1040             }
1041         }
1042
1043
1044       if (bullets[i].alive)
1045         {
1046           for (j = 0; j < NUM_BAD_GUYS; j++)
1047             {
1048               if (bad_guys[j].alive && !bad_guys[j].dying)
1049                 {
1050                   if (bullets[i].x >= bad_guys[j].x - 4 &&
1051                       bullets[i].x <= bad_guys[j].x + 32 + 4 &&
1052                       bullets[i].y >= bad_guys[j].y - 4 &&
1053                       bullets[i].y <= bad_guys[j].y + 32 + 4)
1054                     {
1055                       /* Kill the bad guy! */
1056
1057                       bullets[i].alive = 0;
1058                       bad_guys[j].dying = FALLING;
1059                       bad_guys[j].ym = -8;
1060
1061
1062                       /* Gain some points: */
1063
1064                       if (bad_guys[j].kind == BAD_BSOD)
1065                         {
1066                           add_score(bad_guys[j].x - scroll_x, bad_guys[j].y,
1067                                     50 * score_multiplier);
1068                         }
1069                       else if (bad_guys[j].kind == BAD_LAPTOP)
1070                         {
1071                           add_score(bad_guys[j].x - scroll_x, bad_guys[j].y,
1072                                     25 * score_multiplier);
1073                         }
1074
1075
1076                       /* Play death sound: */
1077                       play_sound(sounds[SND_FALL]);
1078                     }
1079                 }
1080             }
1081         }
1082     }
1083
1084
1085   /* Handle background timer: */
1086
1087   if (super_bkgd_time)
1088     super_bkgd_time--;
1089
1090
1091   /* Handle invincibility timer: */
1092
1093
1094   if (tux_invincible_time > 50)
1095     {
1096       tux_invincible_time--;
1097
1098
1099       if (!playing_music())
1100         play_music( herring_song, 1 );
1101     }
1102   else
1103     {
1104       if (current_music == HERRING_MUSIC)
1105         {
1106           /* stop the herring_song, now play the level_song ! */
1107           current_music = LEVEL_MUSIC;
1108           halt_music();
1109         }
1110       if (!playing_music())
1111         play_music( level_song, 1 );
1112       if (tux_invincible_time > 0)
1113         tux_invincible_time--;
1114     }
1115
1116
1117   /* Handle upgrades: */
1118
1119   for (i = 0; i < NUM_UPGRADES; i++)
1120     {
1121       if (upgrades[i].alive)
1122         {
1123           if (upgrades[i].height < 32)
1124             {
1125               /* Rise up! */
1126
1127               upgrades[i].height++;
1128             }
1129           else
1130             {
1131               /* Move around? */
1132
1133               if (upgrades[i].kind == UPGRADE_MINTS ||
1134                   upgrades[i].kind == UPGRADE_HERRING)
1135                 {
1136                   upgrades[i].x = upgrades[i].x + upgrades[i].xm;
1137                   upgrades[i].y = upgrades[i].y + upgrades[i].ym;
1138
1139                   if (issolid(upgrades[i].x, upgrades[i].y + 31, 0) ||
1140                       issolid(upgrades[i].x + 31, upgrades[i].y + 31, 0))
1141                     {
1142                       if (upgrades[i].ym > 0)
1143                         {
1144                           if (upgrades[i].kind == UPGRADE_MINTS)
1145                             {
1146                               upgrades[i].ym = 0;
1147                             }
1148                           else if (upgrades[i].kind == UPGRADE_HERRING)
1149                             {
1150                               upgrades[i].ym = -24;
1151                             }
1152
1153                           upgrades[i].y = (upgrades[i].y / 32) * 32;
1154                         }
1155                     }
1156                   else
1157                     upgrades[i].ym = upgrades[i].ym + GRAVITY;
1158
1159                   if (issolid(upgrades[i].x, upgrades[i].y, 0))
1160                     {
1161                       upgrades[i].xm = -upgrades[i].xm;
1162                     }
1163                 }
1164
1165
1166               /* Off the screen?  Kill it! */
1167
1168               if (upgrades[i].x < scroll_x)
1169                 upgrades[i].alive = NO;
1170
1171
1172               /* Did the player grab it? */
1173
1174               if (tux_x + scroll_x >= upgrades[i].x - 32 &&
1175                   tux_x + scroll_x <= upgrades[i].x + 32 &&
1176                   tux_y >= upgrades[i].y - 32 &&
1177                   tux_y <= upgrades[i].y + 32)
1178                 {
1179                   /* Remove the upgrade: */
1180
1181                   upgrades[i].alive = NO;
1182
1183
1184                   /* Affect the player: */
1185
1186                   if (upgrades[i].kind == UPGRADE_MINTS)
1187                     {
1188                       play_sound(sounds[SND_EXCELLENT]);
1189                       tux_size = BIG;
1190                       super_bkgd_time = 8;
1191                     }
1192                   else if (upgrades[i].kind == UPGRADE_COFFEE)
1193                     {
1194                       play_sound(sounds[SND_COFFEE]);
1195                       tux_got_coffee = YES;
1196                       super_bkgd_time = 4;
1197                     }
1198                   else if (upgrades[i].kind == UPGRADE_HERRING)
1199                     {
1200                       play_sound(sounds[SND_HERRING]);
1201                       tux_invincible_time = TUX_INVINCIBLE_TIME;
1202                       super_bkgd_time = 4;
1203                       /* play the herring song ^^ */
1204                       current_music = HERRING_MUSIC;
1205                       if (playing_music())
1206                         halt_music();
1207                       play_music( herring_song, 1 );
1208                     }
1209                 }
1210             }
1211         }
1212     }
1213
1214
1215   /* Handle bad guys: */
1216
1217   for (i = 0; i < NUM_BAD_GUYS; i++)
1218     {
1219       if (bad_guys[i].alive)
1220         {
1221           if (bad_guys[i].seen)
1222             {
1223               if (bad_guys[i].kind == BAD_BSOD)
1224                 {
1225                   /* --- BLUE SCREEN OF DEATH MONSTER: --- */
1226
1227                   /* Move left/right: */
1228
1229                   if (bad_guys[i].dying == NO ||
1230                       bad_guys[i].dying == FALLING)
1231                     {
1232                       if (bad_guys[i].dir == RIGHT)
1233                         bad_guys[i].x = bad_guys[i].x + 4;
1234                       else if (bad_guys[i].dir == LEFT)
1235                         bad_guys[i].x = bad_guys[i].x - 4;
1236                     }
1237
1238
1239                   /* Move vertically: */
1240
1241                   bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1242
1243
1244                   /* Bump into things horizontally: */
1245
1246                   if (!bad_guys[i].dying)
1247                     {
1248                       if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
1249                         bad_guys[i].dir = !bad_guys[i].dir;
1250                     }
1251
1252
1253                   /* Bump into other bad guys: */
1254
1255                   for (j = 0; j < NUM_BAD_GUYS; j++)
1256                     {
1257                       if (j != i && bad_guys[j].alive &&
1258                           !bad_guys[j].dying && !bad_guys[i].dying &&
1259                           bad_guys[i].x >= bad_guys[j].x - 32 &&
1260                           bad_guys[i].x <= bad_guys[j].x + 32 &&
1261                           bad_guys[i].y >= bad_guys[j].y - 32 &&
1262                           bad_guys[i].y <= bad_guys[j].y + 32)
1263                         {
1264                           bad_guys[i].dir = !bad_guys[i].dir;
1265                         }
1266                     }
1267
1268
1269                   /* Fall if we get off the ground: */
1270
1271                   if (bad_guys[i].dying != FALLING)
1272                     {
1273                       if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
1274                           bad_guys[i].ym < MAX_YM)
1275                         {
1276                           bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1277                         }
1278                       else
1279                         {
1280                           /* Land: */
1281
1282                           if (bad_guys[i].ym > 0)
1283                             {
1284                               bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1285                               bad_guys[i].ym = 0;
1286                             }
1287                         }
1288                     }
1289                   else
1290                     bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1291
1292                   if (bad_guys[i].y > 480)
1293                     bad_guys[i].alive = NO;
1294                 }
1295               else if (bad_guys[i].kind == BAD_LAPTOP)
1296                 {
1297                   /* --- LAPTOP MONSTER: --- */
1298
1299                   /* Move left/right: */
1300
1301                   if (bad_guys[i].mode != FLAT && bad_guys[i].mode != KICK)
1302                     {
1303                       if (bad_guys[i].dying == NO ||
1304                           bad_guys[i].dying == FALLING)
1305                         {
1306                           if (bad_guys[i].dir == RIGHT)
1307                             bad_guys[i].x = bad_guys[i].x + 4;
1308                           else if (bad_guys[i].dir == LEFT)
1309                             bad_guys[i].x = bad_guys[i].x - 4;
1310                         }
1311                     }
1312                   else if (bad_guys[i].mode == KICK)
1313                     {
1314                       if (bad_guys[i].dir == RIGHT)
1315                         bad_guys[i].x = bad_guys[i].x + 16;
1316                       else if (bad_guys[i].dir == LEFT)
1317                         bad_guys[i].x = bad_guys[i].x - 16;
1318                     }
1319
1320
1321                   /* Move vertically: */
1322
1323                   bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1324
1325
1326                   /* Bump into things horizontally: */
1327
1328                   if (!bad_guys[i].dying)
1329                     {
1330                       if (issolid(bad_guys[i].x, bad_guys[i].y, 0))
1331                         {
1332                           bad_guys[i].dir = !bad_guys[i].dir;
1333
1334                           if (bad_guys[i].mode == KICK)
1335                             play_sound(sounds[SND_RICOCHET]);
1336                         }
1337                     }
1338
1339
1340                   /* Bump into other bad guys: */
1341
1342                   for (j = 0; j < NUM_BAD_GUYS; j++)
1343                     {
1344                       if (j != i && bad_guys[j].alive &&
1345                           !bad_guys[j].dying && !bad_guys[i].dying &&
1346                           bad_guys[i].x >= bad_guys[j].x - 32 &&
1347                           bad_guys[i].x <= bad_guys[j].x + 32 &&
1348                           bad_guys[i].y >= bad_guys[j].y - 32 &&
1349                           bad_guys[i].y <= bad_guys[j].y + 32)
1350                         {
1351                           if (bad_guys[i].mode != KICK)
1352                             bad_guys[i].dir = !bad_guys[i].dir;
1353                           else
1354                             {
1355                               /* We're in kick mode, kill the other guy: */
1356
1357                               bad_guys[j].dying = FALLING;
1358                               bad_guys[j].ym = -8;
1359                               play_sound(sounds[SND_FALL]);
1360
1361                               add_score(bad_guys[i].x - scroll_x,
1362                                         bad_guys[i].y, 100);
1363                             }
1364                         }
1365                     }
1366
1367
1368                   /* Fall if we get off the ground: */
1369
1370                   if (bad_guys[i].dying != FALLING)
1371                     {
1372                       if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) &&
1373                           bad_guys[i].ym < MAX_YM)
1374                         {
1375                           bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1376                         }
1377                       else
1378                         {
1379                           /* Land: */
1380
1381                           if (bad_guys[i].ym > 0)
1382                             {
1383                               bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1384                               bad_guys[i].ym = 0;
1385                             }
1386                         }
1387                     }
1388                   else
1389                     bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1390
1391                   if (bad_guys[i].y > 480)
1392                     bad_guys[i].alive = NO;
1393                 }
1394               else if (bad_guys[i].kind == BAD_MONEY)
1395                 {
1396                   /* --- MONEY BAGS: --- */
1397
1398
1399                   /* Move vertically: */
1400
1401                   bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym;
1402
1403
1404                   /* Fall if we get off the ground: */
1405
1406                   if (bad_guys[i].dying != FALLING)
1407                     {
1408                       if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0))
1409                         {
1410                           if (bad_guys[i].ym < MAX_YM)
1411                             {
1412                               bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1413                             }
1414                         }
1415                       else
1416                         {
1417                           /* Land: */
1418
1419                           if (bad_guys[i].ym > 0)
1420                             {
1421                               bad_guys[i].y = (bad_guys[i].y / 32) * 32;
1422                               bad_guys[i].ym = -MAX_YM;
1423                             }
1424                         }
1425                     }
1426                   else
1427                     bad_guys[i].ym = bad_guys[i].ym + GRAVITY;
1428
1429                   if (bad_guys[i].y > 480)
1430                     bad_guys[i].alive = NO;
1431                 }
1432               else if (bad_guys[i].kind == -1)
1433               {}
1434
1435
1436               /* Kill it if the player jumped on it: */
1437
1438               if (!bad_guys[i].dying && !tux_dying && !tux_safe &&
1439                   tux_x + scroll_x >= bad_guys[i].x - 32 &&
1440                   tux_x + scroll_x <= bad_guys[i].x + 32 &&
1441                   tux_y >= bad_guys[i].y - 32 &&
1442                   tux_y <= bad_guys[i].y - 8
1443                   /* &&
1444                   tux_ym >= 0 */)
1445                 {
1446                   if (bad_guys[i].kind == BAD_BSOD)
1447                     {
1448                       bad_guys[i].dying = SQUISHED;
1449                       bad_guys[i].timer = 16;
1450                       tux_ym = -KILL_BOUNCE_YM;
1451
1452                       add_score(bad_guys[i].x - scroll_x, bad_guys[i].y,
1453                                 50 * score_multiplier);
1454
1455                       play_sound(sounds[SND_SQUISH]);
1456                     }
1457                   else if (bad_guys[i].kind == BAD_LAPTOP)
1458                     {
1459                       if (bad_guys[i].mode != FLAT)
1460                         {
1461                           /* Flatten! */
1462
1463                           bad_guys[i].mode = FLAT;
1464
1465                           bad_guys[i].timer = 64;
1466
1467                           tux_y = tux_y - 32;
1468                         }
1469                       else
1470                         {
1471                           /* Kick! */
1472
1473                           bad_guys[i].mode = KICK;
1474
1475                           if (tux_x + scroll_x <= bad_guys[i].x)
1476                             bad_guys[i].dir = RIGHT;
1477                           else
1478                             bad_guys[i].dir = LEFT;
1479
1480                           bad_guys[i].timer = 8;
1481                         }
1482
1483                       tux_ym = -KILL_BOUNCE_YM;
1484
1485                       add_score(bad_guys[i].x - scroll_x,
1486                                 bad_guys[i].y,
1487                                 25 * score_multiplier);
1488
1489                       /* play_sound(sounds[SND_SQUISH]); */
1490                     }
1491                   else if (bad_guys[i].kind == -1)
1492                   {}
1493
1494                   score_multiplier++;
1495                 }
1496
1497
1498               /* Hurt the player if he just touched it: */
1499
1500               if (!bad_guys[i].dying && !tux_dying &&
1501                   !tux_safe &&
1502                   tux_x + scroll_x >= bad_guys[i].x - 32 &&
1503                   tux_x + scroll_x <= bad_guys[i].x + 32 &&
1504                   tux_y >= bad_guys[i].y - 32 &&
1505                   tux_y <= bad_guys[i].y + 32)
1506                 {
1507                   if (bad_guys[i].mode == FLAT)
1508                     {
1509                       /* Kick: */
1510
1511                       bad_guys[i].mode = KICK;
1512
1513                       if (tux_x + scroll_x <= bad_guys[i].x)
1514                         {
1515                           bad_guys[i].dir = RIGHT;
1516                           bad_guys[i].x = bad_guys[i].x + 16;
1517                         }
1518                       else
1519                         {
1520                           bad_guys[i].dir = LEFT;
1521                           bad_guys[i].x = bad_guys[i].x - 16;
1522                         }
1523
1524                       bad_guys[i].timer = 8;
1525                     }
1526                   else if (bad_guys[i].mode == KICK)
1527                     {
1528                       if (tux_y < bad_guys[i].y - 16 &&
1529                           bad_guys[i].timer == 0)
1530                         {
1531                           /* Step on (stop being kicked) */
1532
1533                           bad_guys[i].mode = FLAT;
1534                           bad_guys[i].timer = 64;
1535                         }
1536                       else
1537                         {
1538                           /* Hurt if you get hit by kicked laptop: */
1539
1540                           if (bad_guys[i].timer == 0)
1541                             {
1542                               if (tux_invincible_time == 0)
1543                                 {
1544                                   killtux(SHRINK);
1545                                 }
1546                               else
1547                                 {
1548                                   bad_guys[i].dying = FALLING;
1549                                   bad_guys[i].ym = -8;
1550                                   play_sound(sounds[SND_FALL]);
1551                                 }
1552                             }
1553                         }
1554                     }
1555                   else
1556                     {
1557                       if (tux_invincible_time == 0)
1558                         {
1559                           killtux(SHRINK);
1560                         }
1561                       else
1562                         {
1563                           bad_guys[i].dying = FALLING;
1564                           bad_guys[i].ym = -8;
1565                           play_sound(sounds[SND_FALL]);
1566                         }
1567                     }
1568                 }
1569
1570
1571               /* Handle mode timer: */
1572
1573               if (bad_guys[i].mode == FLAT)
1574                 {
1575                   bad_guys[i].timer--;
1576
1577                   if (bad_guys[i].timer <= 0)
1578                     bad_guys[i].mode = NORMAL;
1579                 }
1580               else if (bad_guys[i].mode == KICK)
1581                 {
1582                   if (bad_guys[i].timer > 0)
1583                     bad_guys[i].timer--;
1584                 }
1585
1586
1587               /* Handle dying timer: */
1588
1589               if (bad_guys[i].dying == SQUISHED)
1590                 {
1591                   bad_guys[i].timer--;
1592
1593
1594                   /* Remove it if time's up: */
1595
1596                   if (bad_guys[i].timer <= 0)
1597                     bad_guys[i].alive = NO;
1598                 }
1599
1600
1601               /* Remove if it's far off the screen: */
1602
1603               if (bad_guys[i].x < scroll_x - OFFSCREEN_DISTANCE)
1604                 bad_guys[i].alive = NO;
1605             }
1606           else /* !seen */
1607             {
1608               /* Once it's on screen, it's activated! */
1609
1610               if (bad_guys[i].x <= scroll_x + 640 + OFFSCREEN_DISTANCE)
1611                 bad_guys[i].seen = YES;
1612             }
1613         }
1614     }
1615
1616
1617   /* Handle skidding: */
1618
1619   if (tux_skidding > 0)
1620     {
1621       tux_skidding--;
1622     }
1623
1624   return -1;
1625 }
1626
1627 /* --- GAME DRAW! --- */
1628
1629 void game_draw()
1630 {
1631   int  x, y, i;
1632
1633   /* Draw screen: */
1634
1635   if (tux_dying && (frame % 4) == 0)
1636     clearscreen(255, 255, 255);
1637   else
1638     {
1639       if (super_bkgd_time == 0)
1640         clearscreen(bkgd_red, bkgd_green, bkgd_blue);
1641       else
1642         drawimage(img_super_bkgd, 0, 0, NO_UPDATE);
1643     }
1644
1645
1646   /* Draw background: */
1647
1648   for (y = 0; y < 15; y++)
1649     {
1650       for (x = 0; x < 21; x++)
1651         {
1652           drawshape(x * 32 - (scroll_x % 32), y * 32,
1653                     tiles[y][x + (scroll_x / 32)]);
1654         }
1655     }
1656
1657
1658   /* (Bouncy bricks): */
1659
1660   for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
1661     {
1662       if (bouncy_bricks[i].alive)
1663         {
1664           if (bouncy_bricks[i].x >= scroll_x - 32 &&
1665               bouncy_bricks[i].x <= scroll_x + 640)
1666             {
1667               dest.x = bouncy_bricks[i].x - scroll_x;
1668               dest.y = bouncy_bricks[i].y;
1669               dest.w = 32;
1670               dest.h = 32;
1671
1672               SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format,
1673                                                      bkgd_red,
1674                                                      bkgd_green,
1675                                                      bkgd_blue));
1676
1677               drawshape(bouncy_bricks[i].x - scroll_x,
1678                         bouncy_bricks[i].y + bouncy_bricks[i].offset,
1679                         bouncy_bricks[i].shape);
1680             }
1681         }
1682     }
1683
1684
1685   /* (Bad guys): */
1686
1687   for (i = 0; i < NUM_BAD_GUYS; i++)
1688     {
1689       if (bad_guys[i].alive &&
1690           bad_guys[i].x > scroll_x - 32 &&
1691           bad_guys[i].x < scroll_x + 640)
1692         {
1693           if (bad_guys[i].kind == BAD_BSOD)
1694             {
1695               /* --- BLUE SCREEN OF DEATH MONSTER: --- */
1696
1697               if (bad_guys[i].dying == NO)
1698                 {
1699                   /* Alive: */
1700
1701                   if (bad_guys[i].dir == LEFT)
1702                     {
1703                       drawimage(img_bsod_left[(frame / 5) % 4],
1704                                 bad_guys[i].x - scroll_x,
1705                                 bad_guys[i].y,
1706                                 NO_UPDATE);
1707                     }
1708                   else
1709                     {
1710                       drawimage(img_bsod_right[(frame / 5) % 4],
1711                                 bad_guys[i].x - scroll_x,
1712                                 bad_guys[i].y,
1713                                 NO_UPDATE);
1714                     }
1715                 }
1716               else if (bad_guys[i].dying == FALLING)
1717                 {
1718                   /* Falling: */
1719
1720                   if (bad_guys[i].dir == LEFT)
1721                     {
1722                       drawimage(img_bsod_falling_left,
1723                                 bad_guys[i].x - scroll_x,
1724                                 bad_guys[i].y,
1725                                 NO_UPDATE);
1726                     }
1727                   else
1728                     {
1729                       drawimage(img_bsod_falling_right,
1730                                 bad_guys[i].x - scroll_x,
1731                                 bad_guys[i].y,
1732                                 NO_UPDATE);
1733                     }
1734                 }
1735               else if (bad_guys[i].dying == SQUISHED)
1736                 {
1737                   /* Dying - Squished: */
1738
1739                   if (bad_guys[i].dir == LEFT)
1740                     {
1741                       drawimage(img_bsod_squished_left,
1742                                 bad_guys[i].x - scroll_x,
1743                                 bad_guys[i].y + 24,
1744                                 NO_UPDATE);
1745                     }
1746                   else
1747                     {
1748                       drawimage(img_bsod_squished_right,
1749                                 bad_guys[i].x - scroll_x,
1750                                 bad_guys[i].y + 24,
1751                                 NO_UPDATE);
1752                     }
1753                 }
1754             }
1755           else if (bad_guys[i].kind == BAD_LAPTOP)
1756             {
1757               /* --- LAPTOP MONSTER: --- */
1758
1759               if (bad_guys[i].dying == NO)
1760                 {
1761                   /* Alive: */
1762
1763                   if (bad_guys[i].mode == NORMAL)
1764                     {
1765                       /* Not flat: */
1766
1767                       if (bad_guys[i].dir == LEFT)
1768                         {
1769                           drawimage(img_laptop_left[(frame / 5) % 3],
1770                                     bad_guys[i].x - scroll_x,
1771                                     bad_guys[i].y,
1772                                     NO_UPDATE);
1773                         }
1774                       else
1775                         {
1776                           drawimage(img_laptop_right[(frame / 5) % 3],
1777                                     bad_guys[i].x - scroll_x,
1778                                     bad_guys[i].y,
1779                                     NO_UPDATE);
1780                         }
1781                     }
1782                   else
1783                     {
1784                       /* Flat: */
1785
1786                       if (bad_guys[i].dir == LEFT)
1787                         {
1788                           drawimage(img_laptop_flat_left,
1789                                     bad_guys[i].x - scroll_x,
1790                                     bad_guys[i].y,
1791                                     NO_UPDATE);
1792                         }
1793                       else
1794                         {
1795                           drawimage(img_laptop_flat_right,
1796                                     bad_guys[i].x - scroll_x,
1797                                     bad_guys[i].y,
1798                                     NO_UPDATE);
1799                         }
1800                     }
1801                 }
1802               else if (bad_guys[i].dying == FALLING)
1803                 {
1804                   /* Falling: */
1805
1806                   if (bad_guys[i].dir == LEFT)
1807                     {
1808                       drawimage(img_laptop_falling_left,
1809                                 bad_guys[i].x - scroll_x,
1810                                 bad_guys[i].y,
1811                                 NO_UPDATE);
1812                     }
1813                   else
1814                     {
1815                       drawimage(img_laptop_falling_right,
1816                                 bad_guys[i].x - scroll_x,
1817                                 bad_guys[i].y,
1818                                 NO_UPDATE);
1819                     }
1820                 }
1821             }
1822           else if (bad_guys[i].kind == BAD_MONEY)
1823             {
1824               if (bad_guys[i].ym > -16)
1825                 {
1826                   if (bad_guys[i].dir == LEFT)
1827                     {
1828                       drawimage(img_money_left[0],
1829                                 bad_guys[i].x - scroll_x,
1830                                 bad_guys[i].y,
1831                                 NO_UPDATE);
1832                     }
1833                   else
1834                     {
1835                       drawimage(img_money_right[0],
1836                                 bad_guys[i].x - scroll_x,
1837                                 bad_guys[i].y,
1838                                 NO_UPDATE);
1839                     }
1840                 }
1841               else
1842                 {
1843                   if (bad_guys[i].dir == LEFT)
1844                     {
1845                       drawimage(img_money_left[1],
1846                                 bad_guys[i].x - scroll_x,
1847                                 bad_guys[i].y,
1848                                 NO_UPDATE);
1849                     }
1850                   else
1851                     {
1852                       drawimage(img_money_right[1],
1853                                 bad_guys[i].x - scroll_x,
1854                                 bad_guys[i].y,
1855                                 NO_UPDATE);
1856                     }
1857                 }
1858             }
1859           else if (bad_guys[i].kind == -1)
1860           {}
1861         }
1862     }
1863
1864
1865   /* (Tux): */
1866
1867   if (right == UP && left == UP)
1868     {
1869       tux_frame_main = 1;
1870       tux_frame = 1;
1871     }
1872   else
1873     {
1874       if ((fire == DOWN && (frame % 2) == 0) ||
1875           (frame % 4) == 0)
1876         tux_frame_main = (tux_frame_main + 1) % 4;
1877
1878       tux_frame = tux_frame_main;
1879
1880       if (tux_frame == 3)
1881         tux_frame = 1;
1882     }
1883
1884
1885   if (tux_got_coffee && (frame % 2) == 1)
1886     {
1887       /* Coffee glow: */
1888
1889       drawimage(img_red_glow, tux_x - 8, tux_y - 32, NO_UPDATE);
1890     }
1891
1892
1893   if (tux_safe == 0 || (frame % 2) == 0)
1894     {
1895       if (tux_size == SMALL)
1896         {
1897           if (tux_invincible_time)
1898             {
1899               /* Draw cape: */
1900
1901               if (tux_dir == RIGHT)
1902                 {
1903                   drawimage(cape_right[frame % 2],
1904                             tux_x, tux_y,
1905                             NO_UPDATE);
1906                 }
1907               else
1908                 {
1909                   drawimage(cape_left[frame % 2],
1910                             tux_x, tux_y,
1911                             NO_UPDATE);
1912                 }
1913             }
1914
1915
1916           if (tux_dir == RIGHT)
1917             {
1918               drawimage(tux_right[tux_frame], tux_x, tux_y, NO_UPDATE);
1919             }
1920           else
1921             {
1922               drawimage(tux_left[tux_frame], tux_x, tux_y, NO_UPDATE);
1923             }
1924         }
1925       else
1926         {
1927           if (tux_invincible_time)
1928             {
1929               /* Draw cape: */
1930
1931               if (tux_dir == RIGHT)
1932                 {
1933                   drawimage(bigcape_right[frame % 2],
1934                             tux_x - 8 - 16, tux_y - 32,
1935                             NO_UPDATE);
1936                 }
1937               else
1938                 {
1939                   drawimage(bigcape_left[frame % 2],
1940                             tux_x - 8, tux_y - 32,
1941                             NO_UPDATE);
1942                 }
1943             }
1944
1945           if (!tux_duck)
1946             {
1947               if (!tux_skidding)
1948                 {
1949                   if (!jumping || tux_ym > 0)
1950                     {
1951                       if (tux_dir == RIGHT)
1952                         {
1953                           drawimage(bigtux_right[tux_frame],
1954                                     tux_x - 8, tux_y - 32,
1955                                     NO_UPDATE);
1956                         }
1957                       else
1958                         {
1959                           drawimage(bigtux_left[tux_frame],
1960                                     tux_x - 8, tux_y - 32,
1961                                     NO_UPDATE);
1962                         }
1963                     }
1964                   else
1965                     {
1966                       if (tux_dir == RIGHT)
1967                         {
1968                           drawimage(bigtux_right_jump,
1969                                     tux_x - 8, tux_y - 32,
1970                                     NO_UPDATE);
1971                         }
1972                       else
1973                         {
1974                           drawimage(bigtux_left_jump,
1975                                     tux_x - 8, tux_y - 32,
1976                                     NO_UPDATE);
1977                         }
1978                     }
1979                 }
1980               else
1981                 {
1982                   if (tux_dir == RIGHT)
1983                     {
1984                       drawimage(skidtux_right,
1985                                 tux_x - 8, tux_y - 32,
1986                                 NO_UPDATE);
1987                     }
1988                   else
1989                     {
1990                       drawimage(skidtux_left,
1991                                 tux_x - 8, tux_y - 32,
1992                                 NO_UPDATE);
1993                     }
1994                 }
1995             }
1996           else
1997             {
1998               if (tux_dir == RIGHT)
1999                 {
2000                   drawimage(ducktux_right, tux_x - 8, tux_y - 16,
2001                             NO_UPDATE);
2002                 }
2003               else
2004                 {
2005                   drawimage(ducktux_left, tux_x - 8, tux_y - 16,
2006                             NO_UPDATE);
2007                 }
2008             }
2009         }
2010     }
2011
2012
2013   /* (Bullets): */
2014
2015   for (i = 0; i < NUM_BULLETS; i++)
2016     {
2017       if (bullets[i].alive &&
2018           bullets[i].x >= scroll_x - 4 &&
2019           bullets[i].x <= scroll_x + 640)
2020         {
2021           drawimage(img_bullet, bullets[i].x - scroll_x, bullets[i].y,
2022                     NO_UPDATE);
2023         }
2024     }
2025
2026
2027   /* (Floating scores): */
2028
2029   for (i = 0; i < NUM_FLOATING_SCORES; i++)
2030     {
2031       if (floating_scores[i].alive)
2032         {
2033           sprintf(str, "%d", floating_scores[i].value);
2034           drawtext(str,
2035                    floating_scores[i].x + 16 - strlen(str) * 8,
2036                    floating_scores[i].y,
2037                    letters_gold, NO_UPDATE);
2038         }
2039     }
2040
2041
2042   /* (Upgrades): */
2043
2044   for (i = 0; i < NUM_UPGRADES; i++)
2045     {
2046       if (upgrades[i].alive)
2047         {
2048           if (upgrades[i].height < 32)
2049             {
2050               /* Rising up... */
2051
2052               dest.x = upgrades[i].x - scroll_x;
2053               dest.y = upgrades[i].y + 32 - upgrades[i].height;
2054               dest.w = 32;
2055               dest.h = upgrades[i].height;
2056
2057               src.x = 0;
2058               src.y = 0;
2059               src.w = 32;
2060               src.h = upgrades[i].height;
2061
2062               if (upgrades[i].kind == UPGRADE_MINTS)
2063                 SDL_BlitSurface(img_mints, &src, screen, &dest);
2064               else if (upgrades[i].kind == UPGRADE_COFFEE)
2065                 SDL_BlitSurface(img_coffee, &src, screen, &dest);
2066               else if (upgrades[i].kind == UPGRADE_HERRING)
2067                 SDL_BlitSurface(img_golden_herring, &src, screen, &dest);
2068             }
2069           else
2070             {
2071               if (upgrades[i].kind == UPGRADE_MINTS)
2072                 {
2073                   drawimage(img_mints,
2074                             upgrades[i].x - scroll_x, upgrades[i].y,
2075                             NO_UPDATE);
2076                 }
2077               else if (upgrades[i].kind == UPGRADE_COFFEE)
2078                 {
2079                   drawimage(img_coffee,
2080                             upgrades[i].x - scroll_x, upgrades[i].y,
2081                             NO_UPDATE);
2082                 }
2083               else if (upgrades[i].kind == UPGRADE_HERRING)
2084                 {
2085                   drawimage(img_golden_herring,
2086                             upgrades[i].x - scroll_x, upgrades[i].y,
2087                             NO_UPDATE);
2088                 }
2089             }
2090         }
2091     }
2092
2093
2094   /* (Bouncy distros): */
2095
2096   for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
2097     {
2098       if (bouncy_distros[i].alive)
2099         {
2100           drawimage(img_distro[0],
2101                     bouncy_distros[i].x - scroll_x,
2102                     bouncy_distros[i].y,
2103                     NO_UPDATE);
2104         }
2105     }
2106
2107
2108   /* (Broken bricks): */
2109
2110   for (i = 0; i < NUM_BROKEN_BRICKS; i++)
2111     {
2112       if (broken_bricks[i].alive)
2113         {
2114           src.x = rand() % 16;
2115           src.y = rand() % 16;
2116           src.w = 16;
2117           src.h = 16;
2118
2119           dest.x = broken_bricks[i].x - scroll_x;
2120           dest.y = broken_bricks[i].y;
2121           dest.w = 16;
2122           dest.h = 16;
2123
2124           SDL_BlitSurface(img_brick[0], &src, screen, &dest);
2125         }
2126     }
2127
2128
2129   /* (Status): */
2130
2131   sprintf(str, "%d", score);
2132   drawtext("SCORE", 0, 0, letters_blue, NO_UPDATE);
2133   drawtext(str, 96, 0, letters_gold, NO_UPDATE);
2134
2135   sprintf(str, "%d", highscore);
2136   drawtext("HIGH", 0, 20, letters_blue, NO_UPDATE);
2137   drawtext(str, 96, 20, letters_gold, NO_UPDATE);
2138
2139   if (time_left >= 50 || (frame % 10) < 5)
2140     {
2141       sprintf(str, "%d", time_left);
2142       drawtext("TIME", 224, 0, letters_blue, NO_UPDATE);
2143       drawtext(str, 304, 0, letters_gold, NO_UPDATE);
2144     }
2145
2146   sprintf(str, "%d", distros);
2147   drawtext("DISTROS", 480, 0, letters_blue, NO_UPDATE);
2148   drawtext(str, 608, 0, letters_gold, NO_UPDATE);
2149
2150   if(game_pause)
2151     drawcenteredtext("PAUSE",230,letters_red, NO_UPDATE);
2152
2153   if(show_menu)
2154     done = drawmenu();
2155
2156   /* (Update it all!) */
2157
2158   updatescreen();
2159
2160
2161 }
2162
2163 /* --- GAME LOOP! --- */
2164
2165 int gameloop(void)
2166 {
2167
2168   Uint32 last_time, now_time;
2169
2170   /* Clear screen: */
2171
2172   clearscreen(0, 0, 0);
2173   updatescreen();
2174
2175
2176   /* Init the game: */
2177
2178   initmenu();
2179   initgame();
2180   loadshared();
2181   loadlevel();
2182   loadlevelgfx();
2183   loadlevelsong();
2184   highscore = load_hs();
2185
2186
2187   /* --- MAIN GAME LOOP!!! --- */
2188
2189   done = 0;
2190   quit = 0;
2191   frame = 0;
2192   tux_frame_main = 0;
2193   tux_frame = 0;
2194   game_pause = 0;
2195
2196   game_draw();
2197   do
2198     {
2199       last_time = SDL_GetTicks();
2200       frame++;
2201
2202
2203       /* Handle events: */
2204
2205       old_fire = fire;
2206
2207       game_event();
2208
2209       /* Handle actions: */
2210
2211       if(!game_pause && !show_menu)
2212         {
2213           if (game_action() == 0)
2214             {
2215               /* == 0: no more lives */
2216               /* == -1: continues */
2217               return 0;
2218             }
2219         }
2220       else
2221         SDL_Delay(50);
2222
2223       /*Draw the current scene to the screen */
2224       game_draw();
2225
2226       /* Keep playing music: */
2227
2228
2229       if (!playing_music())
2230         {
2231           switch (current_music)
2232             {
2233             case LEVEL_MUSIC:
2234               play_music(level_song, 1);
2235               break;
2236             case HERRING_MUSIC:
2237               play_music(herring_song, 1);
2238               break;
2239             case HURRYUP_MUSIC: // keep the compiler happy
2240             case NO_MUSIC:      // keep the compiler happy for the moment :-)
2241             {}
2242               /*default:*/
2243             }
2244         }
2245
2246       /* Time stops in pause mode */
2247       if(game_pause || show_menu )
2248         {
2249           continue;
2250         }
2251
2252       /* Pause til next frame: */
2253
2254       now_time = SDL_GetTicks();
2255       if (now_time < last_time + FPS)
2256         SDL_Delay(last_time + FPS - now_time);
2257
2258
2259       /* Handle time: */
2260
2261       if ((frame % 10) == 0 && time_left > 0)
2262         {
2263           time_left--;
2264
2265           if (time_left <= 0)
2266             killtux(KILL);
2267         }
2268     }
2269   while (!done && !quit);
2270
2271   if (playing_music())
2272     halt_music();
2273
2274   unloadlevelgfx();
2275   unloadlevelsong();
2276   unloadshared();
2277
2278   return(quit);
2279 }
2280
2281
2282 /* Initialize the game stuff: */
2283
2284 void initgame(void)
2285 {
2286   level = 1;
2287   score = 0;
2288   distros = 0;
2289   lives = 3;
2290 }
2291
2292
2293
2294 /* Load data for this level: */
2295
2296 void loadlevel(void)
2297 {
2298   int i, x, y;
2299   FILE * fi;
2300   char * filename;
2301   char str[80];
2302   char * line;
2303
2304
2305   /* Reset arrays: */
2306
2307   for (i = 0; i < NUM_BOUNCY_DISTROS; i++)
2308     bouncy_distros[i].alive = NO;
2309
2310   for (i = 0; i < NUM_BROKEN_BRICKS; i++)
2311     broken_bricks[i].alive = NO;
2312
2313   for (i = 0; i < NUM_BOUNCY_BRICKS; i++)
2314     bouncy_bricks[i].alive = NO;
2315
2316   for (i = 0; i < NUM_BAD_GUYS; i++)
2317     bad_guys[i].alive = NO;
2318
2319   for (i = 0; i < NUM_FLOATING_SCORES; i++)
2320     floating_scores[i].alive = NO;
2321
2322   for (i = 0; i < NUM_UPGRADES; i++)
2323     upgrades[i].alive = NO;
2324
2325   for (i = 0; i < NUM_BULLETS; i++)
2326     bullets[i].alive = NO;
2327
2328
2329   /* Load data file: */
2330
2331   filename = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) + 20));
2332   sprintf(filename, "%s/levels/level%d.dat", DATA_PREFIX, level);
2333   fi = fopen(filename, "r");
2334   if (fi == NULL)
2335     {
2336       perror(filename);
2337       st_shutdown();
2338       free(filename);
2339       exit(-1);
2340     }
2341   free(filename);
2342
2343
2344   /* Load header info: */
2345
2346
2347   /* (Level title) */
2348   fgets(str, 20, fi);
2349   strcpy(levelname, str);
2350   levelname[strlen(levelname)-1] = '\0';
2351
2352   /* (Level theme) */
2353   fgets(str, 20, fi);
2354   strcpy(leveltheme, str);
2355   leveltheme[strlen(leveltheme)-1] = '\0';
2356
2357
2358
2359   /* (Time to beat level) */
2360   fgets(str, 10, fi);
2361   time_left = atoi(str);
2362
2363   /* (Song file for this level) */
2364   fgets(str, 20, fi);
2365   strcpy(song_title, str);
2366   song_title[strlen(song_title)-1] = '\0';
2367
2368
2369
2370   /* (Level background color) */
2371   fgets(str, 10, fi);
2372   bkgd_red = atoi(str);
2373   fgets(str, 10, fi);
2374   bkgd_green= atoi(str);
2375   fgets(str, 10, fi);
2376   bkgd_blue = atoi(str);
2377
2378   /* (Level width) */
2379   fgets(str, 10, fi);
2380   level_width = atoi(str);
2381
2382
2383   /* Allocate some space for the line-reading! */
2384
2385   line = (char *) malloc(sizeof(char) * (level_width + 5));
2386   if (line == NULL)
2387     {
2388       fprintf(stderr, "Couldn't allocate space to load level data!");
2389       exit(1);
2390     }
2391
2392
2393   /* Load the level lines: */
2394
2395   for (y = 0; y < 15; y++)
2396     {
2397       if(fgets(line, level_width + 5, fi) == NULL)
2398         {
2399           fprintf(stderr, "Level %s isn't complete!\n",levelname);
2400           exit(1);
2401         }
2402       line[strlen(line) - 1] = '\0';
2403       tiles[y] = strdup(line);
2404     }
2405
2406   fclose(fi);
2407
2408
2409   /* Activate bad guys: */
2410
2411   for (y = 0; y < 15; y++)
2412     {
2413       for (x = 0; x < level_width; x++)
2414         {
2415           if (tiles[y][x] >= '0' && tiles[y][x] <= '9')
2416             {
2417               add_bad_guy(x * 32, y * 32, tiles[y][x] - '0');
2418               tiles[y][x] = '.';
2419             }
2420         }
2421     }
2422
2423
2424   /* Set defaults: */
2425
2426   tux_x = 0;
2427   tux_xm = 0;
2428   tux_y = 240;
2429   tux_ym = 0;
2430   tux_dir = RIGHT;
2431   tux_size = SMALL;
2432   tux_got_coffee = NO;
2433   tux_invincible_time = 0;
2434   tux_duck = NO;
2435
2436   tux_dying = NO;
2437   tux_safe = TUX_SAFE_TIME;
2438
2439   jumping = NO;
2440   jump_counter = 0;
2441
2442   tux_skidding = 0;
2443
2444   scroll_x = 0;
2445
2446   right = UP;
2447   left = UP;
2448   up = UP;
2449   down = UP;
2450   fire = UP;
2451   old_fire = UP;
2452
2453   score_multiplier = 1;
2454   super_bkgd_time = 0;
2455
2456   counting_distros = NO;
2457   distro_counter = 0;
2458
2459   endpos = 0;
2460
2461   /* set current song/music */
2462   current_music = LEVEL_MUSIC;
2463
2464   /* Level Intro: */
2465
2466   clearscreen(0, 0, 0);
2467
2468   sprintf(str, "LEVEL %d", level);
2469   drawcenteredtext(str, 200, letters_red, NO_UPDATE);
2470
2471   sprintf(str, "%s", levelname);
2472   drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
2473
2474   sprintf(str, "TUX x %d", lives);
2475   drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
2476
2477   SDL_Flip(screen);
2478
2479   SDL_Delay(1000);
2480
2481
2482 }
2483
2484
2485 /* Load a level-specific graphic... */
2486
2487 SDL_Surface * load_level_image(char * file, int use_alpha)
2488 {
2489   char fname[1024];
2490
2491   snprintf(fname, 1024, "%s/images/%s/%s", DATA_PREFIX, leveltheme, file);
2492
2493   return(load_image(fname, use_alpha));
2494 }
2495
2496
2497 /* Load graphics: */
2498
2499 void loadlevelgfx(void)
2500 {
2501   img_brick[0] = load_level_image("brick0.png", IGNORE_ALPHA);
2502   img_brick[1] = load_level_image("brick1.png", IGNORE_ALPHA);
2503
2504   img_solid[0] = load_level_image("solid0.png", USE_ALPHA);
2505   img_solid[1] = load_level_image("solid1.png", USE_ALPHA);
2506   img_solid[2] = load_level_image("solid2.png", USE_ALPHA);
2507   img_solid[3] = load_level_image("solid3.png", USE_ALPHA);
2508
2509   img_bkgd[0][0] = load_level_image("bkgd-00.png", USE_ALPHA);
2510   img_bkgd[0][1] = load_level_image("bkgd-01.png", USE_ALPHA);
2511   img_bkgd[0][2] = load_level_image("bkgd-02.png", USE_ALPHA);
2512   img_bkgd[0][3] = load_level_image("bkgd-03.png", USE_ALPHA);
2513
2514   img_bkgd[1][0] = load_level_image("bkgd-10.png", USE_ALPHA);
2515   img_bkgd[1][1] = load_level_image("bkgd-11.png", USE_ALPHA);
2516   img_bkgd[1][2] = load_level_image("bkgd-12.png", USE_ALPHA);
2517   img_bkgd[1][3] = load_level_image("bkgd-13.png", USE_ALPHA);
2518 }
2519
2520
2521 /* Load music: */
2522
2523 void loadlevelsong(void)
2524 {
2525
2526   char * song_path;
2527
2528   song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
2529                               strlen(song_title) + 8));
2530
2531   sprintf(song_path, "%s/music/%s", DATA_PREFIX, song_title);
2532
2533   level_song = load_song(song_path);
2534
2535   free(song_path);
2536 }
2537
2538
2539 /* Free graphics data for this level: */
2540
2541 void unloadlevelgfx(void)
2542 {
2543   int i;
2544
2545   for (i = 0; i < 2; i++)
2546     {
2547       SDL_FreeSurface(img_brick[i]);
2548     }
2549   for (i = 0; i < 4; i++)
2550     {
2551       SDL_FreeSurface(img_solid[i]);
2552       SDL_FreeSurface(img_bkgd[0][i]);
2553       SDL_FreeSurface(img_bkgd[1][i]);
2554     }
2555 }
2556
2557
2558 /* Free music data for this level: */
2559
2560 void unloadlevelsong(void)
2561 {
2562   free_music(level_song);
2563 }
2564
2565
2566 /* Load graphics/sounds shared between all levels: */
2567
2568 void loadshared(void)
2569 {
2570   int i;
2571   char * herring_song_path; /* for loading herring song*/
2572
2573   /* Tuxes: */
2574
2575   tux_right[0] = load_image(DATA_PREFIX "/images/shared/tux-right-0.png",
2576                             USE_ALPHA);
2577
2578   tux_right[1] = load_image(DATA_PREFIX "/images/shared/tux-right-1.png",
2579                             USE_ALPHA);
2580
2581   tux_right[2] = load_image(DATA_PREFIX "/images/shared/tux-right-2.png",
2582                             USE_ALPHA);
2583
2584   tux_left[0] = load_image(DATA_PREFIX "/images/shared/tux-left-0.png",
2585                            USE_ALPHA);
2586
2587   tux_left[1] = load_image(DATA_PREFIX "/images/shared/tux-left-1.png",
2588                            USE_ALPHA);
2589
2590   tux_left[2] = load_image(DATA_PREFIX "/images/shared/tux-left-2.png",
2591                            USE_ALPHA);
2592
2593   cape_right[0] = load_image(DATA_PREFIX "/images/shared/cape-right-0.png",
2594                              USE_ALPHA);
2595
2596   cape_right[1] = load_image(DATA_PREFIX "/images/shared/cape-right-1.png",
2597                              USE_ALPHA);
2598
2599   cape_left[0] = load_image(DATA_PREFIX "/images/shared/cape-left-0.png",
2600                             USE_ALPHA);
2601
2602   cape_left[1] = load_image(DATA_PREFIX "/images/shared/cape-left-1.png",
2603                             USE_ALPHA);
2604
2605   bigtux_right[0] = load_image(DATA_PREFIX "/images/shared/bigtux-right-0.png",
2606                                USE_ALPHA);
2607
2608   bigtux_right[1] = load_image(DATA_PREFIX "/images/shared/bigtux-right-1.png",
2609                                USE_ALPHA);
2610
2611   bigtux_right[2] = load_image(DATA_PREFIX "/images/shared/bigtux-right-2.png",
2612                                USE_ALPHA);
2613
2614   bigtux_right_jump =
2615     load_image(DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
2616
2617   bigtux_left[0] = load_image(DATA_PREFIX "/images/shared/bigtux-left-0.png",
2618                               USE_ALPHA);
2619
2620   bigtux_left[1] = load_image(DATA_PREFIX "/images/shared/bigtux-left-1.png",
2621                               USE_ALPHA);
2622
2623   bigtux_left[2] = load_image(DATA_PREFIX "/images/shared/bigtux-left-2.png",
2624                               USE_ALPHA);
2625
2626   bigtux_left_jump =
2627     load_image(DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
2628
2629   bigcape_right[0] =
2630     load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png",
2631                USE_ALPHA);
2632
2633   bigcape_right[1] =
2634     load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png",
2635                USE_ALPHA);
2636
2637   bigcape_left[0] =
2638     load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png",
2639                USE_ALPHA);
2640
2641   bigcape_left[1] =
2642     load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png",
2643                USE_ALPHA);
2644
2645   ducktux_right = load_image(DATA_PREFIX
2646                              "/images/shared/ducktux-right.png",
2647                              USE_ALPHA);
2648
2649   ducktux_left = load_image(DATA_PREFIX
2650                             "/images/shared/ducktux-left.png",
2651                             USE_ALPHA);
2652
2653   skidtux_right = load_image(DATA_PREFIX
2654                              "/images/shared/skidtux-right.png",
2655                              USE_ALPHA);
2656
2657   skidtux_left = load_image(DATA_PREFIX
2658                             "/images/shared/skidtux-left.png",
2659                             USE_ALPHA);
2660
2661
2662   /* Boxes: */
2663
2664   img_box_full = load_image(DATA_PREFIX "/images/shared/box-full.png",
2665                             IGNORE_ALPHA);
2666   img_box_empty = load_image(DATA_PREFIX "/images/shared/box-empty.png",
2667                              IGNORE_ALPHA);
2668
2669
2670   /* Water: */
2671
2672
2673   img_water = load_image(DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
2674
2675   img_waves[0] = load_image(DATA_PREFIX "/images/shared/waves-0.png",
2676                             USE_ALPHA);
2677
2678   img_waves[1] = load_image(DATA_PREFIX "/images/shared/waves-1.png",
2679                             USE_ALPHA);
2680
2681   img_waves[2] = load_image(DATA_PREFIX "/images/shared/waves-2.png",
2682                             USE_ALPHA);
2683
2684
2685   /* Pole: */
2686
2687   img_pole = load_image(DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
2688   img_poletop = load_image(DATA_PREFIX "/images/shared/poletop.png",
2689                            USE_ALPHA);
2690
2691
2692   /* Flag: */
2693
2694   img_flag[0] = load_image(DATA_PREFIX "/images/shared/flag-0.png",
2695                            USE_ALPHA);
2696   img_flag[1] = load_image(DATA_PREFIX "/images/shared/flag-1.png",
2697                            USE_ALPHA);
2698
2699
2700   /* Cloud: */
2701
2702   img_cloud[0][0] = load_image(DATA_PREFIX "/images/shared/cloud-00.png",
2703                                USE_ALPHA);
2704
2705   img_cloud[0][1] = load_image(DATA_PREFIX "/images/shared/cloud-01.png",
2706                                USE_ALPHA);
2707
2708   img_cloud[0][2] = load_image(DATA_PREFIX "/images/shared/cloud-02.png",
2709                                USE_ALPHA);
2710
2711   img_cloud[0][3] = load_image(DATA_PREFIX "/images/shared/cloud-03.png",
2712                                USE_ALPHA);
2713
2714
2715   img_cloud[1][0] = load_image(DATA_PREFIX "/images/shared/cloud-10.png",
2716                                USE_ALPHA);
2717
2718   img_cloud[1][1] = load_image(DATA_PREFIX "/images/shared/cloud-11.png",
2719                                USE_ALPHA);
2720
2721   img_cloud[1][2] = load_image(DATA_PREFIX "/images/shared/cloud-12.png",
2722                                USE_ALPHA);
2723
2724   img_cloud[1][3] = load_image(DATA_PREFIX "/images/shared/cloud-13.png",
2725                                USE_ALPHA);
2726
2727
2728   /* Bad guys: */
2729
2730   /* (BSOD) */
2731
2732   img_bsod_left[0] = load_image(DATA_PREFIX
2733                                 "/images/shared/bsod-left-0.png",
2734                                 USE_ALPHA);
2735
2736   img_bsod_left[1] = load_image(DATA_PREFIX
2737                                 "/images/shared/bsod-left-1.png",
2738                                 USE_ALPHA);
2739
2740   img_bsod_left[2] = load_image(DATA_PREFIX
2741                                 "/images/shared/bsod-left-2.png",
2742                                 USE_ALPHA);
2743
2744   img_bsod_left[3] = load_image(DATA_PREFIX
2745                                 "/images/shared/bsod-left-3.png",
2746                                 USE_ALPHA);
2747
2748   img_bsod_right[0] = load_image(DATA_PREFIX
2749                                  "/images/shared/bsod-right-0.png",
2750                                  USE_ALPHA);
2751
2752   img_bsod_right[1] = load_image(DATA_PREFIX
2753                                  "/images/shared/bsod-right-1.png",
2754                                  USE_ALPHA);
2755
2756   img_bsod_right[2] = load_image(DATA_PREFIX
2757                                  "/images/shared/bsod-right-2.png",
2758                                  USE_ALPHA);
2759
2760   img_bsod_right[3] = load_image(DATA_PREFIX
2761                                  "/images/shared/bsod-right-3.png",
2762                                  USE_ALPHA);
2763
2764   img_bsod_squished_left = load_image(DATA_PREFIX
2765                                       "/images/shared/bsod-squished-left.png",
2766                                       USE_ALPHA);
2767
2768   img_bsod_squished_right = load_image(DATA_PREFIX
2769                                        "/images/shared/bsod-squished-right.png",
2770                                        USE_ALPHA);
2771
2772   img_bsod_falling_left = load_image(DATA_PREFIX
2773                                      "/images/shared/bsod-falling-left.png",
2774                                      USE_ALPHA);
2775
2776   img_bsod_falling_right = load_image(DATA_PREFIX
2777                                       "/images/shared/bsod-falling-right.png",
2778                                       USE_ALPHA);
2779
2780
2781   /* (Laptop) */
2782
2783   img_laptop_left[0] = load_image(DATA_PREFIX
2784                                   "/images/shared/laptop-left-0.png",
2785                                   USE_ALPHA);
2786
2787   img_laptop_left[1] = load_image(DATA_PREFIX
2788                                   "/images/shared/laptop-left-1.png",
2789                                   USE_ALPHA);
2790
2791   img_laptop_left[2] = load_image(DATA_PREFIX
2792                                   "/images/shared/laptop-left-2.png",
2793                                   USE_ALPHA);
2794
2795   img_laptop_right[0] = load_image(DATA_PREFIX
2796                                    "/images/shared/laptop-right-0.png",
2797                                    USE_ALPHA);
2798
2799   img_laptop_right[1] = load_image(DATA_PREFIX
2800                                    "/images/shared/laptop-right-1.png",
2801                                    USE_ALPHA);
2802
2803   img_laptop_right[2] = load_image(DATA_PREFIX
2804                                    "/images/shared/laptop-right-2.png",
2805                                    USE_ALPHA);
2806
2807   img_laptop_flat_left = load_image(DATA_PREFIX
2808                                     "/images/shared/laptop-flat-left.png",
2809                                     USE_ALPHA);
2810
2811   img_laptop_flat_right = load_image(DATA_PREFIX
2812                                      "/images/shared/laptop-flat-right.png",
2813                                      USE_ALPHA);
2814
2815   img_laptop_falling_left =
2816     load_image(DATA_PREFIX
2817                "/images/shared/laptop-falling-left.png",
2818                USE_ALPHA);
2819
2820   img_laptop_falling_right =
2821     load_image(DATA_PREFIX
2822                "/images/shared/laptop-falling-right.png",
2823                USE_ALPHA);
2824
2825
2826   /* (Money) */
2827
2828   img_money_left[0] = load_image(DATA_PREFIX
2829                                  "/images/shared/bag-left-0.png",
2830                                  USE_ALPHA);
2831
2832   img_money_left[1] = load_image(DATA_PREFIX
2833                                  "/images/shared/bag-left-1.png",
2834                                  USE_ALPHA);
2835
2836   img_money_right[0] = load_image(DATA_PREFIX
2837                                   "/images/shared/bag-right-0.png",
2838                                   USE_ALPHA);
2839
2840   img_money_right[1] = load_image(DATA_PREFIX
2841                                   "/images/shared/bag-right-1.png",
2842                                   USE_ALPHA);
2843
2844
2845
2846   /* Upgrades: */
2847
2848   img_mints = load_image(DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
2849   img_coffee = load_image(DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
2850
2851
2852   /* Weapons: */
2853
2854   img_bullet = load_image(DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
2855
2856   img_red_glow = load_image(DATA_PREFIX "/images/shared/red-glow.png",
2857                             USE_ALPHA);
2858
2859
2860   /* Distros: */
2861
2862   img_distro[0] = load_image(DATA_PREFIX "/images/shared/distro-0.png",
2863                              USE_ALPHA);
2864
2865   img_distro[1] = load_image(DATA_PREFIX "/images/shared/distro-1.png",
2866                              USE_ALPHA);
2867
2868   img_distro[2] = load_image(DATA_PREFIX "/images/shared/distro-2.png",
2869                              USE_ALPHA);
2870
2871   img_distro[3] = load_image(DATA_PREFIX "/images/shared/distro-3.png",
2872                              USE_ALPHA);
2873
2874
2875   /* Herring: */
2876
2877   img_golden_herring =
2878     load_image(DATA_PREFIX "/images/shared/golden-herring.png",
2879                USE_ALPHA);
2880
2881
2882   /* Super background: */
2883
2884   img_super_bkgd = load_image(DATA_PREFIX "/images/shared/super-bkgd.png",
2885                               IGNORE_ALPHA);
2886
2887
2888   /* Sound effects: */
2889
2890   /*  if (use_sound) // this can help speeding up a little, but
2891      we shouldn't take care about "use_sound" here, it's load_sound's job
2892      / Send a mail to neoneurone@users.sf.net, if you have another opinion. :)
2893      */
2894   for (i = 0; i < NUM_SOUNDS; i++)
2895     sounds[i] = load_sound(soundfilenames[i]);
2896
2897   /* Herring song */
2898   herring_song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
2899                                       strlen("SALCON.MOD") + 8)); /* FIXME: We need a real herring_song! Thats a fake.:) */
2900
2901   sprintf(herring_song_path, "%s/music/%s", DATA_PREFIX, "SALCON.MOD");
2902
2903   herring_song = load_song(herring_song_path);
2904
2905   free(herring_song_path);
2906
2907 }
2908
2909
2910 /* Free shared data: */
2911
2912 void unloadshared(void)
2913 {
2914   int i;
2915
2916   for (i = 0; i < 3; i++)
2917     {
2918       SDL_FreeSurface(tux_right[i]);
2919       SDL_FreeSurface(tux_left[i]);
2920       SDL_FreeSurface(bigtux_right[i]);
2921       SDL_FreeSurface(bigtux_left[i]);
2922     }
2923
2924   SDL_FreeSurface(bigtux_right_jump);
2925   SDL_FreeSurface(bigtux_left_jump);
2926
2927   for (i = 0; i < 2; i++)
2928     {
2929       SDL_FreeSurface(cape_right[i]);
2930       SDL_FreeSurface(cape_left[i]);
2931       SDL_FreeSurface(bigcape_right[i]);
2932       SDL_FreeSurface(bigcape_left[i]);
2933     }
2934
2935   SDL_FreeSurface(ducktux_left);
2936   SDL_FreeSurface(ducktux_right);
2937
2938   SDL_FreeSurface(skidtux_left);
2939   SDL_FreeSurface(skidtux_right);
2940
2941   for (i = 0; i < 4; i++)
2942     {
2943       SDL_FreeSurface(img_bsod_left[i]);
2944       SDL_FreeSurface(img_bsod_right[i]);
2945     }
2946
2947   SDL_FreeSurface(img_bsod_squished_left);
2948   SDL_FreeSurface(img_bsod_squished_right);
2949
2950   SDL_FreeSurface(img_bsod_falling_left);
2951   SDL_FreeSurface(img_bsod_falling_right);
2952
2953   for (i = 0; i < 3; i++)
2954     {
2955       SDL_FreeSurface(img_laptop_left[i]);
2956       SDL_FreeSurface(img_laptop_right[i]);
2957     }
2958
2959   SDL_FreeSurface(img_laptop_flat_left);
2960   SDL_FreeSurface(img_laptop_flat_right);
2961
2962   SDL_FreeSurface(img_laptop_falling_left);
2963   SDL_FreeSurface(img_laptop_falling_right);
2964
2965   for (i = 0; i < 2; i++)
2966     {
2967       SDL_FreeSurface(img_money_left[i]);
2968       SDL_FreeSurface(img_money_right[i]);
2969     }
2970
2971   SDL_FreeSurface(img_box_full);
2972   SDL_FreeSurface(img_box_empty);
2973
2974   SDL_FreeSurface(img_water);
2975   for (i = 0; i < 3; i++)
2976     SDL_FreeSurface(img_waves[i]);
2977
2978   SDL_FreeSurface(img_pole);
2979   SDL_FreeSurface(img_poletop);
2980
2981   for (i = 0; i < 2; i++)
2982     SDL_FreeSurface(img_flag[i]);
2983
2984   SDL_FreeSurface(img_mints);
2985   SDL_FreeSurface(img_coffee);
2986
2987   for (i = 0; i < 4; i++)
2988     {
2989       SDL_FreeSurface(img_distro[i]);
2990       SDL_FreeSurface(img_cloud[0][i]);
2991       SDL_FreeSurface(img_cloud[1][i]);
2992     }
2993
2994   SDL_FreeSurface(img_golden_herring);
2995
2996   for (i = 0; i < NUM_SOUNDS; i++)
2997     free_chunk(sounds[i]);
2998
2999   /* free the herring song */
3000   free_music( herring_song );
3001 }
3002
3003
3004 /* Draw a tile on the screen: */
3005
3006 void drawshape(int x, int y, unsigned char c)
3007 {
3008   int z;
3009
3010   if (c == 'X' || c == 'x')
3011     drawimage(img_brick[0], x, y, NO_UPDATE);
3012   else if (c == 'Y' || c == 'y')
3013     drawimage(img_brick[1], x, y, NO_UPDATE);
3014   else if (c == 'A' || c =='B' || c == '!')
3015     drawimage(img_box_full, x, y, NO_UPDATE);
3016   else if (c == 'a')
3017     drawimage(img_box_empty, x, y, NO_UPDATE);
3018   else if (c >= 'C' && c <= 'F')
3019     drawimage(img_cloud[0][c - 'C'], x, y, NO_UPDATE);
3020   else if (c >= 'c' && c <= 'f')
3021     drawimage(img_cloud[1][c - 'c'], x, y, NO_UPDATE);
3022   else if (c >= 'G' && c <= 'J')
3023     drawimage(img_bkgd[0][c - 'G'], x, y, NO_UPDATE);
3024   else if (c >= 'g' && c <= 'j')
3025     drawimage(img_bkgd[1][c - 'g'], x, y, NO_UPDATE);
3026   else if (c == '#')
3027     drawimage(img_solid[0], x, y, NO_UPDATE);
3028   else if (c == '[')
3029     drawimage(img_solid[1], x, y, NO_UPDATE);
3030   else if (c == '=')
3031     drawimage(img_solid[2], x, y, NO_UPDATE);
3032   else if (c == ']')
3033     drawimage(img_solid[3], x, y, NO_UPDATE);
3034   else if (c == '$')
3035     {
3036       z = (frame / 2) % 6;
3037
3038       if (z < 4)
3039         drawimage(img_distro[z], x, y, NO_UPDATE);
3040       else if (z == 4)
3041         drawimage(img_distro[2], x, y, NO_UPDATE);
3042       else if (z == 5)
3043         drawimage(img_distro[1], x, y, NO_UPDATE);
3044     }
3045   else if (c == '^')
3046     {
3047       z = (frame / 3) % 3;
3048
3049       drawimage(img_waves[z], x, y, NO_UPDATE);
3050     }
3051   else if (c == '*')
3052     drawimage(img_poletop, x, y, NO_UPDATE);
3053   else if (c == '|')
3054     {
3055       drawimage(img_pole, x, y, NO_UPDATE);
3056
3057       /* Mark this as the end position of the level! */
3058
3059       endpos = x;
3060     }
3061   else if (c == '\\')
3062     {
3063       z = (frame / 3) % 2;
3064
3065       drawimage(img_flag[z], x + 16, y, NO_UPDATE);
3066     }
3067   else if (c == '&')
3068     drawimage(img_water, x, y, NO_UPDATE);
3069 }
3070
3071
3072 /* What shape is at some position? */
3073
3074 unsigned char shape(int x, int y, int sx)
3075 {
3076   int xx, yy;
3077   unsigned char c;
3078
3079   yy = (y / 32);
3080   xx = ((x + sx) / 32);
3081
3082   if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= level_width)
3083     c = tiles[yy][xx];
3084   else
3085     c = '.';
3086
3087   return(c);
3088 }
3089
3090
3091 /* Is is ground? */
3092
3093 int issolid(int x, int y, int sx)
3094 {
3095   int v;
3096
3097   v = 0;
3098
3099   if (isbrick(x, y, sx) ||
3100       isbrick(x + 31, y, sx) ||
3101       isice(x, y, sx) ||
3102       isice(x + 31, y, sx) ||
3103       (shape(x, y, sx) == '[' ||
3104        shape(x + 31, y, sx) == '[') ||
3105       (shape(x, y, sx) == '=' ||
3106        shape(x + 31, y, sx) == '=') ||
3107       (shape(x, y, sx) == ']' ||
3108        shape(x + 31, y, sx) == ']') ||
3109       (shape(x, y, sx) == 'A' ||
3110        shape(x + 31, y, sx) == 'A') ||
3111       (shape(x, y, sx) == 'B' ||
3112        shape(x + 31, y, sx) == 'B') ||
3113       (shape(x, y, sx) == '!' ||
3114        shape(x + 31, y, sx) == '!') ||
3115       (shape(x, y, sx) == 'a' ||
3116        shape(x + 31, y, sx) == 'a'))
3117     {
3118       v = 1;
3119     }
3120
3121   return(v);
3122 }
3123
3124
3125 /* Is it a brick? */
3126
3127 int isbrick(int x, int y, int sx)
3128 {
3129   int v;
3130
3131   v = 0;
3132
3133   if (shape(x, y, sx) == 'X' ||
3134       shape(x, y, sx) == 'x' ||
3135       shape(x, y, sx) == 'Y' ||
3136       shape(x, y, sx) == 'y')
3137     {
3138       v = 1;
3139     }
3140
3141   return(v);
3142 }
3143
3144
3145 /* Is it ice? */
3146
3147 int isice(int x, int y, int sx)
3148 {
3149   int v;
3150
3151   v = 0;
3152
3153   if (shape(x, y, sx) == '#')
3154     {
3155       v = 1;
3156     }
3157
3158   return(v);
3159 }
3160
3161
3162 /* Is it a full box? */
3163
3164 int isfullbox(int x, int y, int sx)
3165 {
3166   int v;
3167
3168   v = 0;
3169
3170   if (shape(x, y, sx) == 'A' ||
3171       shape(x, y, sx) == 'B' ||
3172       shape(x, y, sx) == '!')
3173     {
3174       v = 1;
3175     }
3176
3177   return(v);
3178 }
3179
3180
3181 /* Edit a piece of the map! */
3182
3183 void change(int x, int y, int sx, unsigned char c)
3184 {
3185   int xx, yy;
3186
3187   yy = (y / 32);
3188   xx = ((x + sx) / 32);
3189
3190   if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= level_width)
3191     tiles[yy][xx] = c;
3192 }
3193
3194
3195 /* Break a brick: */
3196
3197 void trybreakbrick(int x, int y, int sx)
3198 {
3199   if (isbrick(x, y, sx))
3200     {
3201       if (shape(x, y, sx) == 'x' || shape(x, y, sx) == 'y')
3202         {
3203           /* Get a distro from it: */
3204
3205           add_bouncy_distro(((x + sx + 1) / 32) * 32,
3206                             (y / 32) * 32);
3207
3208           if (counting_distros == NO)
3209             {
3210               counting_distros = YES;
3211               distro_counter = 50;
3212             }
3213
3214           if (distro_counter <= 0)
3215             change(x, y, sx, 'a');
3216
3217           play_sound(sounds[SND_DISTRO]);
3218           score = score + SCORE_DISTRO;
3219           distros++;
3220         }
3221       else
3222         {
3223           /* Get rid of it: */
3224
3225           change(x, y, sx, '.');
3226         }
3227
3228
3229       /* Replace it with broken bits: */
3230
3231       add_broken_brick(((x + sx + 1) / 32) * 32,
3232                        (y / 32) * 32);
3233
3234
3235       /* Get some score: */
3236
3237       play_sound(sounds[SND_BRICK]);
3238       score = score + SCORE_BRICK;
3239     }
3240 }
3241
3242
3243 /* Bounce a brick: */
3244
3245 void bumpbrick(int x, int y, int sx)
3246 {
3247   add_bouncy_brick(((x + sx + 1) / 32) * 32,
3248                    (y / 32) * 32);
3249
3250   play_sound(sounds[SND_BRICK]);
3251 }
3252
3253
3254 /* Empty a box: */
3255
3256 void tryemptybox(int x, int y, int sx)
3257 {
3258   if (isfullbox(x, y, sx))
3259     {
3260       if (shape(x, y, sx) == 'A')
3261         {
3262           /* Box with a distro! */
3263
3264           add_bouncy_distro(((x + sx + 1) / 32) * 32,
3265                             (y / 32) * 32 - 32);
3266
3267           play_sound(sounds[SND_DISTRO]);
3268           score = score + SCORE_DISTRO;
3269           distros++;
3270         }
3271       else if (shape(x, y, sx) == 'B')
3272         {
3273           /* Add an upgrade! */
3274
3275           if (tux_size == SMALL)
3276             {
3277               /* Tux is small, add mints! */
3278
3279               add_upgrade(((x + sx + 1) / 32) * 32,
3280                           (y / 32) * 32 - 32,
3281                           UPGRADE_MINTS);
3282             }
3283           else
3284             {
3285               /* Tux is big, add coffee: */
3286
3287               add_upgrade(((x + sx + 1) / 32) * 32,
3288                           (y / 32) * 32 - 32,
3289                           UPGRADE_COFFEE);
3290             }
3291
3292           play_sound(sounds[SND_UPGRADE]);
3293         }
3294       else if (shape(x, y, sx) == '!')
3295         {
3296           /* Add a golden herring */
3297
3298           add_upgrade(((x + sx + 1) / 32) * 32,
3299                       (y / 32) * 32 - 32,
3300                       UPGRADE_HERRING);
3301         }
3302
3303       /* Empty the box: */
3304
3305       change(x, y, sx, 'a');
3306     }
3307 }
3308
3309
3310 /* Try to grab a distro: */
3311
3312 void trygrabdistro(int x, int y, int sx, int bounciness)
3313 {
3314   if (shape(x, y, sx) == '$')
3315     {
3316       change(x, y, sx, '.');
3317       play_sound(sounds[SND_DISTRO]);
3318
3319       if (bounciness == BOUNCE)
3320         {
3321           add_bouncy_distro(((x + sx + 1) / 32) * 32,
3322                             (y / 32) * 32);
3323         }
3324
3325       score = score + SCORE_DISTRO;
3326       distros++;
3327     }
3328 }
3329
3330
3331 /* Add a bouncy distro: */
3332
3333 void add_bouncy_distro(int x, int y)
3334 {
3335   int i, found;
3336
3337   found = -1;
3338
3339   for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++)
3340     {
3341       if (!bouncy_distros[i].alive)
3342         found = i;
3343     }
3344
3345   if (found != -1)
3346     {
3347       bouncy_distros[found].alive = YES;
3348       bouncy_distros[found].x = x;
3349       bouncy_distros[found].y = y;
3350       bouncy_distros[found].ym = -6;
3351     }
3352 }
3353
3354
3355 /* Add broken brick pieces: */
3356
3357 void add_broken_brick(int x, int y)
3358 {
3359   add_broken_brick_piece(x, y, -4, -16);
3360   add_broken_brick_piece(x, y + 16, -6, -12);
3361
3362   add_broken_brick_piece(x + 16, y, 4, -16);
3363   add_broken_brick_piece(x + 16, y + 16, 6, -12);
3364 }
3365
3366
3367 /* Add a broken brick piece: */
3368
3369 void add_broken_brick_piece(int x, int y, int xm, int ym)
3370 {
3371   int i, found;
3372
3373   found = -1;
3374
3375   for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++)
3376     {
3377       if (!broken_bricks[i].alive)
3378         found = i;
3379     }
3380
3381   if (found != -1)
3382     {
3383       broken_bricks[found].alive = YES;
3384       broken_bricks[found].x = x;
3385       broken_bricks[found].y = y;
3386       broken_bricks[found].xm = xm;
3387       broken_bricks[found].ym = ym;
3388     }
3389 }
3390
3391
3392 /* Add a bouncy brick piece: */
3393
3394 void add_bouncy_brick(int x, int y)
3395 {
3396   int i, found;
3397
3398   found = -1;
3399
3400   for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++)
3401     {
3402       if (!bouncy_bricks[i].alive)
3403         found = i;
3404     }
3405
3406   if (found != -1)
3407     {
3408       bouncy_bricks[found].alive = YES;
3409       bouncy_bricks[found].x = x;
3410       bouncy_bricks[found].y = y;
3411       bouncy_bricks[found].offset = 0;
3412       bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED;
3413       bouncy_bricks[found].shape = shape(x, y, 0);
3414     }
3415 }
3416
3417
3418 /* Add a bad guy: */
3419
3420 void add_bad_guy(int x, int y, int kind)
3421 {
3422   int i, found;
3423
3424   found = -1;
3425
3426   for (i = 0; i < NUM_BAD_GUYS && found == -1; i++)
3427     {
3428       if (!bad_guys[i].alive)
3429         found = i;
3430     }
3431
3432   if (found != -1)
3433     {
3434       bad_guys[found].alive = YES;
3435       bad_guys[found].mode = NORMAL;
3436       bad_guys[found].dying = NO;
3437       bad_guys[found].timer = 0;
3438       bad_guys[found].kind = kind;
3439       bad_guys[found].x = x;
3440       bad_guys[found].y = y;
3441       bad_guys[found].xm = 0;
3442       bad_guys[found].ym = 0;
3443       bad_guys[found].dir = LEFT;
3444       bad_guys[found].seen = NO;
3445     }
3446 }
3447
3448
3449 /* Add score: */
3450
3451 void add_score(int x, int y, int s)
3452 {
3453   int i, found;
3454
3455
3456   /* Add the score: */
3457
3458   score = score + s;
3459
3460
3461   /* Add a floating score thing to the game: */
3462
3463   found = -1;
3464
3465   for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++)
3466     {
3467       if (!floating_scores[i].alive)
3468         found = i;
3469     }
3470
3471
3472   if (found != -1)
3473     {
3474       floating_scores[found].alive = YES;
3475       floating_scores[found].x = x;
3476       floating_scores[found].y = y - 16;
3477       floating_scores[found].timer = 8;
3478       floating_scores[found].value = s;
3479     }
3480 }
3481
3482
3483 /* Try to bump a bad guy from below: */
3484
3485 void trybumpbadguy(int x, int y, int sx)
3486 {
3487   int i;
3488
3489
3490   /* Bad guys: */
3491
3492   for (i = 0; i < NUM_BAD_GUYS; i++)
3493     {
3494       if (bad_guys[i].alive &&
3495           bad_guys[i].x >= x + sx - 32 && bad_guys[i].x <= x + sx + 32 &&
3496           bad_guys[i].y >= y - 16 && bad_guys[i].y <= y + 16)
3497         {
3498           if (bad_guys[i].kind == BAD_BSOD ||
3499               bad_guys[i].kind == BAD_LAPTOP)
3500             {
3501               bad_guys[i].dying = FALLING;
3502               bad_guys[i].ym = -8;
3503               play_sound(sounds[SND_FALL]);
3504             }
3505         }
3506     }
3507
3508
3509   /* Upgrades: */
3510
3511   for (i = 0; i < NUM_UPGRADES; i++)
3512     {
3513       if (upgrades[i].alive && upgrades[i].height == 32 &&
3514           upgrades[i].x >= x + sx - 32 && upgrades[i].x <= x + sx + 32 &&
3515           upgrades[i].y >= y - 16 && upgrades[i].y <= y + 16)
3516         {
3517           upgrades[i].xm = -upgrades[i].xm;
3518           upgrades[i].ym = -8;
3519           play_sound(sounds[SND_BUMP_UPGRADE]);
3520         }
3521     }
3522 }
3523
3524
3525 /* Add an upgrade: */
3526
3527 void add_upgrade(int x, int y, int kind)
3528 {
3529   int i, found;
3530
3531   found = -1;
3532
3533   for (i = 0; i < NUM_UPGRADES && found == -1; i++)
3534     {
3535       if (!upgrades[i].alive)
3536         found = i;
3537     }
3538
3539   if (found != -1)
3540     {
3541       upgrades[found].alive = YES;
3542       upgrades[found].kind = kind;
3543       upgrades[found].x = x;
3544       upgrades[found].y = y;
3545       upgrades[found].xm = 4;
3546       upgrades[found].ym = -4;
3547       upgrades[found].height = 0;
3548     }
3549 }
3550
3551
3552 /* Kill tux! */
3553
3554 void killtux(int mode)
3555 {
3556   tux_ym = -16;
3557
3558   play_sound(sounds[SND_HURT]);
3559
3560   if (tux_dir == RIGHT)
3561     tux_xm = -8;
3562   else if (tux_dir == LEFT)
3563     tux_xm = 8;
3564
3565   if (mode == SHRINK && tux_size == BIG)
3566     {
3567       if (tux_got_coffee)
3568         tux_got_coffee = NO;
3569
3570       tux_size = SMALL;
3571
3572       tux_safe = TUX_SAFE_TIME;
3573     }
3574   else
3575     {
3576       tux_dying = 1;
3577     }
3578 }
3579
3580
3581 /* Add a bullet: */
3582
3583 void add_bullet(int x, int y, int dir, int xm)
3584 {
3585   int i, found;
3586
3587   found = -1;
3588
3589   for (i = 0; i < NUM_BULLETS && found == -1; i++)
3590     {
3591       if (!bullets[i].alive)
3592         found = i;
3593     }
3594
3595   if (found != -1)
3596     {
3597       bullets[found].alive = YES;
3598
3599       if (dir == RIGHT)
3600         {
3601           bullets[found].x = x + 32;
3602           bullets[found].xm = BULLET_XM + xm;
3603         }
3604       else
3605         {
3606           bullets[found].x = x;
3607           bullets[found].xm = -BULLET_XM + xm;
3608         }
3609
3610       bullets[found].y = y;
3611       bullets[found].ym = BULLET_STARTING_YM;
3612
3613       play_sound(sounds[SND_SHOOT]);
3614     }
3615 }
3616
3617
3618 void drawendscreen(void)
3619 {
3620   char str[80];
3621
3622   clearscreen(0, 0, 0);
3623
3624   drawcenteredtext("GAMEOVER", 200, letters_red, NO_UPDATE);
3625
3626   sprintf(str, "SCORE: %d", score);
3627   drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
3628
3629   sprintf(str, "DISTROS: %d", distros);
3630   drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
3631
3632   SDL_Flip(screen);
3633   SDL_Delay(2000);
3634 }
3635
3636 void drawresultscreen(void)
3637 {
3638   char str[80];
3639
3640   clearscreen(0, 0, 0);
3641
3642   drawcenteredtext("Result:", 200, letters_red, NO_UPDATE);
3643
3644   sprintf(str, "SCORE: %d", score);
3645   drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
3646
3647   sprintf(str, "DISTROS: %d", distros);
3648   drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
3649
3650   SDL_Flip(screen);
3651   /*SDL_Delay(2000);*/
3652   sleep(2);
3653 }
3654
3655