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