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