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