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