applied patch from Duong-Khang NGUYEN <neoneurone@users.sf.net>, which
[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                       play_sound(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                       play_sound(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                             play_sound(sounds[SND_JUMP]);
448                           else
449                             play_sound(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 (playing_music())
503              halt_music();
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                               play_sound(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                               play_sound(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         play_sound(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                           play_sound(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                           play_sound(sounds[SND_EXCELLENT]);
1145                           tux_size = BIG;
1146                           super_bkgd_time = 8;
1147                         }
1148                       else if (upgrades[i].kind == UPGRADE_COFFEE)
1149                         {
1150                           play_sound(sounds[SND_COFFEE]);
1151                           tux_got_coffee = YES;
1152                           super_bkgd_time = 4;
1153                         }
1154                       else if (upgrades[i].kind == UPGRADE_HERRING)
1155                         {
1156                           play_sound(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                                 play_sound(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                                   play_sound(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                           play_sound(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                           /* play_sound(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                                       play_sound(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                               play_sound(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 (!playing_music())
2172             {
2173               play_music(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 (playing_music())
2202         halt_music();
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   DEBUG_MSG("Fatal: FIXME QUICKLY : SEGMENTATION FAULT POSSIBLE !");
2264   sprintf(filename, "%s/levels/level%d.dat", DATA_PREFIX, level);
2265   fi = fopen(filename, "r");
2266   if (fi == NULL)
2267     {
2268       perror(filename);
2269       st_shutdown();
2270       free(filename);
2271       exit(-1);
2272     }
2273   free(filename);
2274
2275
2276   /* Load header info: */
2277
2278   
2279   /* (Level title) */
2280   fgets(str, 20, fi);
2281   strcpy(levelname, str);
2282   levelname[strlen(levelname)-1] = '\0';
2283   
2284   /* (Level theme) */
2285   fgets(str, 20, fi);
2286   strcpy(leveltheme, str);
2287   leveltheme[strlen(leveltheme)-1] = '\0';
2288
2289   
2290
2291   /* (Time to beat level) */
2292   fgets(str, 10, fi);
2293   time_left = atoi(str);
2294
2295   /* (Song file for this level) */
2296   fgets(str, 20, fi);
2297   strcpy(song_title, str);
2298   song_title[strlen(song_title)-1] = '\0';
2299
2300   
2301   
2302   /* (Level background color) */
2303   fgets(str, 10, fi);
2304   bkgd_red = atoi(str);
2305   fgets(str, 10, fi);
2306   bkgd_green= atoi(str);
2307   fgets(str, 10, fi);
2308   bkgd_blue = atoi(str);
2309
2310   /* (Level width) */
2311   fgets(str, 10, fi);
2312   level_width = atoi(str);
2313
2314
2315   /* Allocate some space for the line-reading! */
2316
2317   line = (char *) malloc(sizeof(char) * (level_width + 5));
2318   if (line == NULL)
2319   {
2320     fprintf(stderr, "Couldn't allocate space to load level data!");
2321     exit(1);
2322   }
2323
2324
2325   /* Load the level lines: */
2326
2327   for (y = 0; y < 15; y++)
2328     {
2329       if(fgets(line, level_width + 5, fi) == NULL)
2330       {
2331        fprintf(stderr, "Level %s isn't complete!\n",levelname);
2332        exit(1);
2333       }
2334       line[strlen(line) - 1] = '\0';
2335       tiles[y] = strdup(line);
2336     }
2337   
2338   fclose(fi);
2339   
2340   
2341   /* Activate bad guys: */
2342   
2343   for (y = 0; y < 15; y++)
2344     {
2345       for (x = 0; x < level_width; x++)
2346         {
2347           if (tiles[y][x] >= '0' && tiles[y][x] <= '9')
2348             {
2349               add_bad_guy(x * 32, y * 32, tiles[y][x] - '0');
2350               tiles[y][x] = '.';
2351             }
2352         }
2353     }
2354   
2355   
2356   /* Set defaults: */
2357   
2358   tux_x = 0;
2359   tux_xm = 0;
2360   tux_y = 240;
2361   tux_ym = 0;
2362   tux_dir = RIGHT;
2363   tux_size = SMALL;
2364   tux_got_coffee = NO;
2365   tux_invincible_time = 0;
2366   tux_duck = NO;
2367   
2368   tux_dying = NO;
2369   tux_safe = TUX_SAFE_TIME;
2370   
2371   jumping = NO;
2372   jump_counter = 0;
2373   
2374   tux_skidding = 0;
2375   
2376   scroll_x = 0;
2377   
2378   right = UP;
2379   left = UP;
2380   up = UP;
2381   down = UP;
2382   fire = UP;
2383   old_fire = UP;
2384   
2385   score_multiplier = 1;
2386   super_bkgd_time = 0;
2387   
2388   time_left = 255;
2389
2390   counting_distros = NO;
2391   distro_counter = 0;
2392   
2393   
2394   /* Level Intro: */
2395   
2396   clearscreen(0, 0, 0);
2397   
2398   sprintf(str, "LEVEL %d", level);
2399   drawcenteredtext(str, 200, letters_red, NO_UPDATE);
2400   
2401   sprintf(str, "%s", levelname);
2402   drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
2403   
2404   sprintf(str, "TUX x %d", lives);
2405   drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
2406
2407   SDL_Flip(screen);
2408   
2409   SDL_Delay(1000);
2410
2411   
2412 }
2413
2414
2415 /* Load a level-specific graphic... */
2416
2417 SDL_Surface * load_level_image(char * file, int use_alpha)
2418 {
2419   char fname[1024];
2420
2421   snprintf(fname, 1024, "%s/images/%s/%s", DATA_PREFIX, leveltheme, file);
2422
2423   return(load_image(fname, use_alpha));
2424 }
2425
2426
2427 /* Load graphics: */
2428
2429 void loadlevelgfx(void)
2430 {
2431   img_brick[0] = load_level_image("brick0.png", IGNORE_ALPHA);
2432   img_brick[1] = load_level_image("brick1.png", IGNORE_ALPHA);
2433
2434   img_solid[0] = load_level_image("solid0.png", USE_ALPHA);
2435   img_solid[1] = load_level_image("solid1.png", USE_ALPHA);
2436   img_solid[2] = load_level_image("solid2.png", USE_ALPHA);
2437   img_solid[3] = load_level_image("solid3.png", USE_ALPHA);
2438
2439   img_bkgd[0][0] = load_level_image("bkgd-00.png", USE_ALPHA);
2440   img_bkgd[0][1] = load_level_image("bkgd-01.png", USE_ALPHA);
2441   img_bkgd[0][2] = load_level_image("bkgd-02.png", USE_ALPHA);
2442   img_bkgd[0][3] = load_level_image("bkgd-03.png", USE_ALPHA);
2443
2444   img_bkgd[1][0] = load_level_image("bkgd-10.png", USE_ALPHA);
2445   img_bkgd[1][1] = load_level_image("bkgd-11.png", USE_ALPHA);
2446   img_bkgd[1][2] = load_level_image("bkgd-12.png", USE_ALPHA);
2447   img_bkgd[1][3] = load_level_image("bkgd-13.png", USE_ALPHA);
2448 }
2449
2450
2451 /* Load music: */
2452
2453 void loadlevelsong(void)
2454 {
2455
2456   char * song_path;
2457
2458   song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) +
2459                                               strlen(song_title) + 8));
2460
2461   sprintf(song_path, "%s/music/%s", DATA_PREFIX, song_title);
2462
2463   song = load_song(song_path);
2464
2465   free(song_path);
2466 }
2467
2468
2469 /* Free graphics data for this level: */
2470
2471 void unloadlevelgfx(void)
2472 {
2473   int i;
2474   
2475   for (i = 0; i < 2; i++)
2476     {
2477       SDL_FreeSurface(img_brick[i]);
2478     }
2479   for (i = 0; i < 4; i++)
2480     {
2481       SDL_FreeSurface(img_solid[i]);
2482       SDL_FreeSurface(img_bkgd[0][i]);
2483       SDL_FreeSurface(img_bkgd[1][i]);
2484     }
2485 }
2486
2487
2488 /* Free music data for this level: */
2489
2490 void unloadlevelsong(void)
2491 {
2492   free_music(song);
2493 }
2494
2495
2496 /* Load graphics shared between all levels: */
2497
2498 void loadshared(void)
2499 {
2500   int i;
2501   
2502   
2503   /* Tuxes: */
2504   
2505   tux_right[0] = load_image(DATA_PREFIX "/images/shared/tux-right-0.png",
2506                             USE_ALPHA);
2507
2508   tux_right[1] = load_image(DATA_PREFIX "/images/shared/tux-right-1.png",
2509                             USE_ALPHA);
2510
2511   tux_right[2] = load_image(DATA_PREFIX "/images/shared/tux-right-2.png",
2512                             USE_ALPHA);
2513
2514   tux_left[0] = load_image(DATA_PREFIX "/images/shared/tux-left-0.png",
2515                            USE_ALPHA);
2516
2517   tux_left[1] = load_image(DATA_PREFIX "/images/shared/tux-left-1.png",
2518                            USE_ALPHA);
2519
2520   tux_left[2] = load_image(DATA_PREFIX "/images/shared/tux-left-2.png",
2521                            USE_ALPHA);
2522
2523   cape_right[0] = load_image(DATA_PREFIX "/images/shared/cape-right-0.png",
2524                              USE_ALPHA);
2525
2526   cape_right[1] = load_image(DATA_PREFIX "/images/shared/cape-right-1.png",
2527                              USE_ALPHA);
2528
2529   cape_left[0] = load_image(DATA_PREFIX "/images/shared/cape-left-0.png",
2530                             USE_ALPHA);
2531
2532   cape_left[1] = load_image(DATA_PREFIX "/images/shared/cape-left-1.png",
2533                             USE_ALPHA);
2534
2535   bigtux_right[0] = load_image(DATA_PREFIX "/images/shared/bigtux-right-0.png",
2536                                USE_ALPHA);
2537
2538   bigtux_right[1] = load_image(DATA_PREFIX "/images/shared/bigtux-right-1.png",
2539                                USE_ALPHA);
2540
2541   bigtux_right[2] = load_image(DATA_PREFIX "/images/shared/bigtux-right-2.png",
2542                                USE_ALPHA);
2543
2544   bigtux_right_jump =
2545     load_image(DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA);
2546
2547   bigtux_left[0] = load_image(DATA_PREFIX "/images/shared/bigtux-left-0.png",
2548                               USE_ALPHA);
2549
2550   bigtux_left[1] = load_image(DATA_PREFIX "/images/shared/bigtux-left-1.png",
2551                               USE_ALPHA);
2552
2553   bigtux_left[2] = load_image(DATA_PREFIX "/images/shared/bigtux-left-2.png",
2554                               USE_ALPHA);
2555   
2556   bigtux_left_jump =
2557     load_image(DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA);
2558
2559   bigcape_right[0] =
2560     load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png",
2561                USE_ALPHA);
2562
2563   bigcape_right[1] =
2564     load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png",
2565                USE_ALPHA);
2566
2567   bigcape_left[0] =
2568     load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png",
2569                USE_ALPHA);
2570
2571   bigcape_left[1] =
2572     load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png",
2573                USE_ALPHA);
2574
2575   ducktux_right = load_image(DATA_PREFIX
2576                              "/images/shared/ducktux-right.png",
2577                              USE_ALPHA);
2578
2579   ducktux_left = load_image(DATA_PREFIX
2580                             "/images/shared/ducktux-left.png",
2581                             USE_ALPHA);
2582
2583   skidtux_right = load_image(DATA_PREFIX
2584                              "/images/shared/skidtux-right.png",
2585                              USE_ALPHA);
2586
2587   skidtux_left = load_image(DATA_PREFIX
2588                             "/images/shared/skidtux-left.png",
2589                             USE_ALPHA);
2590   
2591   
2592   /* Boxes: */
2593   
2594   img_box_full = load_image(DATA_PREFIX "/images/shared/box-full.png",
2595                             IGNORE_ALPHA);
2596   img_box_empty = load_image(DATA_PREFIX "/images/shared/box-empty.png",
2597                              IGNORE_ALPHA);
2598   
2599   
2600   /* Water: */
2601   
2602
2603   img_water = load_image(DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA);
2604
2605   img_waves[0] = load_image(DATA_PREFIX "/images/shared/waves-0.png",
2606                             USE_ALPHA);
2607
2608   img_waves[1] = load_image(DATA_PREFIX "/images/shared/waves-1.png",
2609                             USE_ALPHA);
2610
2611   img_waves[2] = load_image(DATA_PREFIX "/images/shared/waves-2.png",
2612                             USE_ALPHA);
2613
2614
2615   /* Pole: */
2616
2617   img_pole = load_image(DATA_PREFIX "/images/shared/pole.png", USE_ALPHA);
2618   img_poletop = load_image(DATA_PREFIX "/images/shared/poletop.png",
2619                            USE_ALPHA);
2620
2621
2622   /* Flag: */
2623
2624   img_flag[0] = load_image(DATA_PREFIX "/images/shared/flag-0.png",
2625                            USE_ALPHA);
2626   img_flag[1] = load_image(DATA_PREFIX "/images/shared/flag-1.png",
2627                            USE_ALPHA);
2628
2629
2630   /* Cloud: */
2631
2632   img_cloud[0][0] = load_image(DATA_PREFIX "/images/shared/cloud-00.png",
2633                                USE_ALPHA);
2634
2635   img_cloud[0][1] = load_image(DATA_PREFIX "/images/shared/cloud-01.png",
2636                                USE_ALPHA);
2637
2638   img_cloud[0][2] = load_image(DATA_PREFIX "/images/shared/cloud-02.png",
2639                                USE_ALPHA);
2640
2641   img_cloud[0][3] = load_image(DATA_PREFIX "/images/shared/cloud-03.png",
2642                                USE_ALPHA);
2643
2644
2645   img_cloud[1][0] = load_image(DATA_PREFIX "/images/shared/cloud-10.png",
2646                                USE_ALPHA);
2647   
2648   img_cloud[1][1] = load_image(DATA_PREFIX "/images/shared/cloud-11.png",
2649                                USE_ALPHA);
2650   
2651   img_cloud[1][2] = load_image(DATA_PREFIX "/images/shared/cloud-12.png",
2652                                USE_ALPHA);
2653   
2654   img_cloud[1][3] = load_image(DATA_PREFIX "/images/shared/cloud-13.png",
2655                                USE_ALPHA);
2656   
2657   
2658   /* Bad guys: */
2659   
2660   /* (BSOD) */
2661   
2662   img_bsod_left[0] = load_image(DATA_PREFIX
2663                                 "/images/shared/bsod-left-0.png",
2664                                 USE_ALPHA);
2665   
2666   img_bsod_left[1] = load_image(DATA_PREFIX
2667                                 "/images/shared/bsod-left-1.png",
2668                                 USE_ALPHA);
2669
2670   img_bsod_left[2] = load_image(DATA_PREFIX
2671                                 "/images/shared/bsod-left-2.png",
2672                                 USE_ALPHA);
2673
2674   img_bsod_left[3] = load_image(DATA_PREFIX
2675                                 "/images/shared/bsod-left-3.png",
2676                                 USE_ALPHA);
2677
2678   img_bsod_right[0] = load_image(DATA_PREFIX
2679                                  "/images/shared/bsod-right-0.png",
2680                                  USE_ALPHA);
2681
2682   img_bsod_right[1] = load_image(DATA_PREFIX
2683                                  "/images/shared/bsod-right-1.png",
2684                                  USE_ALPHA);
2685
2686   img_bsod_right[2] = load_image(DATA_PREFIX
2687                                  "/images/shared/bsod-right-2.png",
2688                                  USE_ALPHA);
2689   
2690   img_bsod_right[3] = load_image(DATA_PREFIX
2691                                  "/images/shared/bsod-right-3.png",
2692                                  USE_ALPHA);
2693
2694   img_bsod_squished_left = load_image(DATA_PREFIX
2695                                   "/images/shared/bsod-squished-left.png",
2696                                   USE_ALPHA);
2697
2698   img_bsod_squished_right = load_image(DATA_PREFIX
2699                                    "/images/shared/bsod-squished-right.png",
2700                                    USE_ALPHA);
2701
2702   img_bsod_falling_left = load_image(DATA_PREFIX
2703                                   "/images/shared/bsod-falling-left.png",
2704                                   USE_ALPHA);
2705
2706   img_bsod_falling_right = load_image(DATA_PREFIX
2707                                    "/images/shared/bsod-falling-right.png",
2708                                    USE_ALPHA);
2709
2710
2711   /* (Laptop) */
2712
2713   img_laptop_left[0] = load_image(DATA_PREFIX
2714                                   "/images/shared/laptop-left-0.png",
2715                                   USE_ALPHA);
2716
2717   img_laptop_left[1] = load_image(DATA_PREFIX
2718                                   "/images/shared/laptop-left-1.png",
2719                                   USE_ALPHA);
2720
2721   img_laptop_left[2] = load_image(DATA_PREFIX
2722                                   "/images/shared/laptop-left-2.png",
2723                                   USE_ALPHA);
2724
2725   img_laptop_right[0] = load_image(DATA_PREFIX
2726                                   "/images/shared/laptop-right-0.png",
2727                                   USE_ALPHA);
2728
2729   img_laptop_right[1] = load_image(DATA_PREFIX
2730                                   "/images/shared/laptop-right-1.png",
2731                                   USE_ALPHA);
2732
2733   img_laptop_right[2] = load_image(DATA_PREFIX
2734                                   "/images/shared/laptop-right-2.png",
2735                                   USE_ALPHA);
2736
2737   img_laptop_flat_left = load_image(DATA_PREFIX
2738                                     "/images/shared/laptop-flat-left.png",
2739                                     USE_ALPHA);
2740
2741   img_laptop_flat_right = load_image(DATA_PREFIX
2742                                      "/images/shared/laptop-flat-right.png",
2743                                      USE_ALPHA);
2744
2745   img_laptop_falling_left =
2746     load_image(DATA_PREFIX
2747                "/images/shared/laptop-falling-left.png",
2748                USE_ALPHA);
2749
2750   img_laptop_falling_right =
2751     load_image(DATA_PREFIX
2752                "/images/shared/laptop-falling-right.png",
2753                USE_ALPHA);
2754
2755
2756   /* (Money) */
2757
2758   img_money_left[0] = load_image(DATA_PREFIX
2759                                  "/images/shared/bag-left-0.png",
2760                                  USE_ALPHA);
2761
2762   img_money_left[1] = load_image(DATA_PREFIX
2763                                  "/images/shared/bag-left-1.png",
2764                                  USE_ALPHA);
2765
2766   img_money_right[0] = load_image(DATA_PREFIX
2767                                   "/images/shared/bag-right-0.png",
2768                                   USE_ALPHA);
2769
2770   img_money_right[1] = load_image(DATA_PREFIX
2771                                   "/images/shared/bag-right-1.png",
2772                                   USE_ALPHA);
2773
2774
2775
2776   /* Upgrades: */
2777
2778   img_mints = load_image(DATA_PREFIX "/images/shared/mints.png", USE_ALPHA);
2779   img_coffee = load_image(DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA);
2780
2781
2782   /* Weapons: */
2783
2784   img_bullet = load_image(DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA);
2785
2786   img_red_glow = load_image(DATA_PREFIX "/images/shared/red-glow.png",
2787                             USE_ALPHA);
2788
2789
2790   /* Distros: */
2791
2792   img_distro[0] = load_image(DATA_PREFIX "/images/shared/distro-0.png",
2793                              USE_ALPHA);
2794
2795   img_distro[1] = load_image(DATA_PREFIX "/images/shared/distro-1.png",
2796                              USE_ALPHA);
2797
2798   img_distro[2] = load_image(DATA_PREFIX "/images/shared/distro-2.png",
2799                              USE_ALPHA);
2800
2801   img_distro[3] = load_image(DATA_PREFIX "/images/shared/distro-3.png",
2802                              USE_ALPHA);
2803
2804
2805   /* Herring: */
2806
2807   img_golden_herring =
2808     load_image(DATA_PREFIX "/images/shared/golden-herring.png",
2809                USE_ALPHA);
2810
2811
2812   /* Super background: */
2813
2814   img_super_bkgd = load_image(DATA_PREFIX "/images/shared/super-bkgd.png",
2815                               IGNORE_ALPHA);
2816
2817
2818   /* Sound effects: */
2819
2820   if (use_sound)
2821     {
2822       for (i = 0; i < NUM_SOUNDS; i++)
2823         sounds[i] = load_sound(soundfilenames[i]);
2824         
2825     }
2826 }
2827
2828
2829 /* Free shared data: */
2830
2831 void unloadshared(void)
2832 {
2833   int i;
2834   
2835   for (i = 0; i < 3; i++)
2836     {
2837       SDL_FreeSurface(tux_right[i]);
2838       SDL_FreeSurface(tux_left[i]);
2839       SDL_FreeSurface(bigtux_right[i]);
2840       SDL_FreeSurface(bigtux_left[i]);
2841     }
2842   
2843   SDL_FreeSurface(bigtux_right_jump);
2844   SDL_FreeSurface(bigtux_left_jump);
2845   
2846   for (i = 0; i < 2; i++)
2847     {
2848       SDL_FreeSurface(cape_right[i]);
2849       SDL_FreeSurface(cape_left[i]);
2850       SDL_FreeSurface(bigcape_right[i]);
2851       SDL_FreeSurface(bigcape_left[i]);
2852     }
2853   
2854   SDL_FreeSurface(ducktux_left);
2855   SDL_FreeSurface(ducktux_right);
2856
2857   SDL_FreeSurface(skidtux_left);
2858   SDL_FreeSurface(skidtux_right);
2859   
2860   for (i = 0; i < 4; i++)
2861     {
2862       SDL_FreeSurface(img_bsod_left[i]);
2863       SDL_FreeSurface(img_bsod_right[i]);
2864     }
2865
2866   SDL_FreeSurface(img_bsod_squished_left);
2867   SDL_FreeSurface(img_bsod_squished_right);
2868
2869   SDL_FreeSurface(img_bsod_falling_left);
2870   SDL_FreeSurface(img_bsod_falling_right);
2871
2872   for (i = 0; i < 3; i++)
2873     {
2874       SDL_FreeSurface(img_laptop_left[i]);
2875       SDL_FreeSurface(img_laptop_right[i]);
2876     }
2877   
2878   SDL_FreeSurface(img_laptop_flat_left);
2879   SDL_FreeSurface(img_laptop_flat_right);
2880
2881   SDL_FreeSurface(img_laptop_falling_left);
2882   SDL_FreeSurface(img_laptop_falling_right);
2883   
2884   for (i = 0; i < 2; i++)
2885     {
2886       SDL_FreeSurface(img_money_left[i]);
2887       SDL_FreeSurface(img_money_right[i]);
2888     }
2889
2890   SDL_FreeSurface(img_box_full);
2891   SDL_FreeSurface(img_box_empty);
2892   
2893   SDL_FreeSurface(img_water);
2894   for (i = 0; i < 3; i++)
2895     SDL_FreeSurface(img_waves[i]);
2896   
2897   SDL_FreeSurface(img_pole);
2898   SDL_FreeSurface(img_poletop);
2899   
2900   for (i = 0; i < 2; i++)
2901     SDL_FreeSurface(img_flag[i]);
2902   
2903   SDL_FreeSurface(img_mints);
2904   SDL_FreeSurface(img_coffee);
2905   
2906   for (i = 0; i < 4; i++)
2907     {
2908       SDL_FreeSurface(img_distro[i]);
2909       SDL_FreeSurface(img_cloud[0][i]);
2910       SDL_FreeSurface(img_cloud[1][i]);
2911     }
2912   
2913   SDL_FreeSurface(img_golden_herring);
2914
2915   for (i = 0; i < NUM_SOUNDS; i++)
2916     free_chunk(sounds[i]);
2917 }
2918
2919
2920 /* Draw a tile on the screen: */
2921
2922 void drawshape(int x, int y, unsigned char c)
2923 {
2924   int z;
2925   
2926   if (c == 'X' || c == 'x')
2927     drawimage(img_brick[0], x, y, NO_UPDATE);
2928   else if (c == 'Y' || c == 'y')
2929     drawimage(img_brick[1], x, y, NO_UPDATE);
2930   else if (c == 'A' || c =='B' || c == '!')
2931     drawimage(img_box_full, x, y, NO_UPDATE);
2932   else if (c == 'a')
2933     drawimage(img_box_empty, x, y, NO_UPDATE);
2934   else if (c >= 'C' && c <= 'F')
2935     drawimage(img_cloud[0][c - 'C'], x, y, NO_UPDATE);
2936   else if (c >= 'c' && c <= 'f')
2937     drawimage(img_cloud[1][c - 'c'], x, y, NO_UPDATE);
2938   else if (c >= 'G' && c <= 'J')
2939     drawimage(img_bkgd[0][c - 'G'], x, y, NO_UPDATE);
2940   else if (c >= 'g' && c <= 'j')
2941     drawimage(img_bkgd[1][c - 'g'], x, y, NO_UPDATE);
2942   else if (c == '#')
2943     drawimage(img_solid[0], x, y, NO_UPDATE);
2944   else if (c == '[')
2945     drawimage(img_solid[1], x, y, NO_UPDATE);
2946   else if (c == '=')
2947     drawimage(img_solid[2], x, y, NO_UPDATE);
2948   else if (c == ']')
2949     drawimage(img_solid[3], x, y, NO_UPDATE);
2950   else if (c == '$')
2951     {
2952       z = (frame / 2) % 6;
2953       
2954       if (z < 4)
2955         drawimage(img_distro[z], x, y, NO_UPDATE);
2956       else if (z == 4)
2957         drawimage(img_distro[2], x, y, NO_UPDATE);
2958       else if (z == 5)
2959         drawimage(img_distro[1], x, y, NO_UPDATE);
2960     }
2961   else if (c == '^')
2962     {
2963       z = (frame / 3) % 3;
2964       
2965       drawimage(img_waves[z], x, y, NO_UPDATE);
2966     }
2967   else if (c == '*')
2968     drawimage(img_poletop, x, y, NO_UPDATE);
2969   else if (c == '|')
2970   {
2971     drawimage(img_pole, x, y, NO_UPDATE);
2972
2973     /* Mark this as the end position of the level! */
2974
2975     endpos = x;
2976   }
2977   else if (c == '\\')
2978     {
2979       z = (frame / 3) % 2;
2980       
2981       drawimage(img_flag[z], x + 16, y, NO_UPDATE);
2982     }
2983   else if (c == '&')
2984     drawimage(img_water, x, y, NO_UPDATE);
2985 }
2986
2987
2988 /* What shape is at some position? */
2989
2990 unsigned char shape(int x, int y, int sx)
2991 {
2992   int xx, yy;
2993   unsigned char c;
2994   
2995   yy = (y / 32);
2996   xx = ((x + sx) / 32);
2997   
2998   if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= level_width)
2999     c = tiles[yy][xx];
3000   else
3001     c = '.';
3002   
3003   return(c);
3004 }
3005
3006
3007 /* Is is ground? */
3008
3009 int issolid(int x, int y, int sx)
3010 {
3011   int v;
3012   
3013   v = 0;
3014   
3015   if (isbrick(x, y, sx) ||
3016       isbrick(x + 31, y, sx) ||
3017       isice(x, y, sx) ||
3018       isice(x + 31, y, sx) ||
3019       (shape(x, y, sx) == '[' ||
3020        shape(x + 31, y, sx) == '[') ||
3021       (shape(x, y, sx) == '=' ||
3022        shape(x + 31, y, sx) == '=') ||
3023       (shape(x, y, sx) == ']' ||
3024        shape(x + 31, y, sx) == ']') ||
3025       (shape(x, y, sx) == 'A' ||
3026        shape(x + 31, y, sx) == 'A') ||
3027       (shape(x, y, sx) == 'B' ||
3028        shape(x + 31, y, sx) == 'B') ||
3029       (shape(x, y, sx) == '!' ||
3030        shape(x + 31, y, sx) == '!') ||
3031       (shape(x, y, sx) == 'a' ||
3032        shape(x + 31, y, sx) == 'a'))
3033     {
3034       v = 1;
3035     }
3036
3037   return(v);
3038 }
3039
3040
3041 /* Is it a brick? */
3042
3043 int isbrick(int x, int y, int sx)
3044 {
3045   int v;
3046   
3047   v = 0;
3048   
3049   if (shape(x, y, sx) == 'X' ||
3050       shape(x, y, sx) == 'x' ||
3051       shape(x, y, sx) == 'Y' ||
3052       shape(x, y, sx) == 'y')
3053     {
3054       v = 1;
3055     }
3056   
3057   return(v);
3058 }
3059
3060
3061 /* Is it ice? */
3062
3063 int isice(int x, int y, int sx)
3064 {
3065   int v;
3066   
3067   v = 0;
3068   
3069   if (shape(x, y, sx) == '#')
3070     {
3071       v = 1;
3072     }
3073   
3074   return(v);
3075 }
3076
3077
3078 /* Is it a full box? */
3079
3080 int isfullbox(int x, int y, int sx)
3081 {
3082   int v;
3083   
3084   v = 0;
3085   
3086   if (shape(x, y, sx) == 'A' ||
3087       shape(x, y, sx) == 'B' ||
3088       shape(x, y, sx) == '!')
3089     {
3090       v = 1;
3091     }
3092   
3093   return(v);
3094 }
3095
3096
3097 /* Edit a piece of the map! */
3098
3099 void change(int x, int y, int sx, unsigned char c)
3100 {
3101   int xx, yy;
3102   
3103   yy = (y / 32);
3104   xx = ((x + sx) / 32);
3105   
3106   if (yy >= 0 && yy <= 15 && xx >= 0 && xx <= level_width)
3107     tiles[yy][xx] = c;
3108 }
3109
3110
3111 /* Break a brick: */
3112
3113 void trybreakbrick(int x, int y, int sx)
3114 {
3115   if (isbrick(x, y, sx))
3116     {
3117       if (shape(x, y, sx) == 'x' || shape(x, y, sx) == 'y')
3118         {
3119           /* Get a distro from it: */
3120           
3121           add_bouncy_distro(((x + sx + 1) / 32) * 32,
3122                             (y / 32) * 32);
3123
3124           if (counting_distros == NO)
3125             {
3126               counting_distros = YES;
3127               distro_counter = 50;
3128             }
3129
3130           if (distro_counter <= 0)
3131            change(x, y, sx, 'a');
3132          
3133           play_sound(sounds[SND_DISTRO]);
3134           score = score + SCORE_DISTRO;
3135           distros++;
3136         }
3137       else
3138       {
3139         /* Get rid of it: */
3140       
3141         change(x, y, sx, '.');
3142       }
3143       
3144       
3145       /* Replace it with broken bits: */
3146       
3147       add_broken_brick(((x + sx + 1) / 32) * 32,
3148                        (y / 32) * 32);
3149       
3150       
3151       /* Get some score: */
3152       
3153       play_sound(sounds[SND_BRICK]);
3154       score = score + SCORE_BRICK;
3155     }
3156 }
3157
3158
3159 /* Bounce a brick: */
3160
3161 void bumpbrick(int x, int y, int sx)
3162 {
3163   add_bouncy_brick(((x + sx + 1) / 32) * 32,
3164                    (y / 32) * 32);
3165   
3166   play_sound(sounds[SND_BRICK]);
3167 }
3168
3169
3170 /* Empty a box: */
3171
3172 void tryemptybox(int x, int y, int sx)
3173 {
3174   if (isfullbox(x, y, sx))
3175     {
3176       if (shape(x, y, sx) == 'A')
3177         {
3178           /* Box with a distro! */
3179           
3180           add_bouncy_distro(((x + sx + 1) / 32) * 32,
3181                             (y / 32) * 32 - 32);
3182           
3183           play_sound(sounds[SND_DISTRO]);
3184           score = score + SCORE_DISTRO;
3185           distros++;
3186         }
3187       else if (shape(x, y, sx) == 'B')
3188         {
3189           /* Add an upgrade! */
3190           
3191           if (tux_size == SMALL)
3192             {
3193               /* Tux is small, add mints! */
3194               
3195               add_upgrade(((x + sx + 1) / 32) * 32,
3196                           (y / 32) * 32 - 32,
3197                           UPGRADE_MINTS);
3198             }
3199           else
3200             {
3201               /* Tux is big, add coffee: */
3202               
3203               add_upgrade(((x + sx + 1) / 32) * 32,
3204                           (y / 32) * 32 - 32,
3205                           UPGRADE_COFFEE);
3206             }
3207           
3208           play_sound(sounds[SND_UPGRADE]);
3209         }
3210       else if (shape(x, y, sx) == '!')
3211         {
3212           /* Add a golden herring */
3213           
3214           add_upgrade(((x + sx + 1) / 32) * 32,
3215                       (y / 32) * 32 - 32,
3216                       UPGRADE_HERRING);
3217         }
3218       
3219       /* Empty the box: */
3220       
3221       change(x, y, sx, 'a');
3222     }
3223 }
3224
3225
3226 /* Try to grab a distro: */
3227
3228 void trygrabdistro(int x, int y, int sx, int bounciness)
3229 {
3230   if (shape(x, y, sx) == '$')
3231     {
3232       change(x, y, sx, '.');
3233       play_sound(sounds[SND_DISTRO]);
3234       
3235       if (bounciness == BOUNCE)
3236         {
3237           add_bouncy_distro(((x + sx + 1) / 32) * 32,
3238                             (y / 32) * 32);
3239         }
3240       
3241       score = score + SCORE_DISTRO;
3242       distros++;
3243     }
3244 }
3245
3246
3247 /* Add a bouncy distro: */
3248
3249 void add_bouncy_distro(int x, int y)
3250 {
3251   int i, found;
3252   
3253   found = -1;
3254   
3255   for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++)
3256     {
3257       if (!bouncy_distros[i].alive)
3258         found = i;
3259     }
3260   
3261   if (found != -1)
3262     {
3263       bouncy_distros[found].alive = YES;
3264       bouncy_distros[found].x = x;
3265       bouncy_distros[found].y = y;
3266       bouncy_distros[found].ym = -6;
3267     }
3268 }
3269
3270
3271 /* Add broken brick pieces: */
3272
3273 void add_broken_brick(int x, int y)
3274 {
3275   add_broken_brick_piece(x, y, -4, -16);
3276   add_broken_brick_piece(x, y + 16, -6, -12);
3277
3278   add_broken_brick_piece(x + 16, y, 4, -16);
3279   add_broken_brick_piece(x + 16, y + 16, 6, -12);
3280 }
3281
3282
3283 /* Add a broken brick piece: */
3284
3285 void add_broken_brick_piece(int x, int y, int xm, int ym)
3286 {
3287   int i, found;
3288   
3289   found = -1;
3290   
3291   for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++)
3292     {
3293       if (!broken_bricks[i].alive)
3294         found = i;
3295     }
3296   
3297   if (found != -1)
3298     {
3299       broken_bricks[found].alive = YES;
3300       broken_bricks[found].x = x;
3301       broken_bricks[found].y = y;
3302       broken_bricks[found].xm = xm;
3303       broken_bricks[found].ym = ym;
3304     }
3305 }
3306
3307
3308 /* Add a bouncy brick piece: */
3309
3310 void add_bouncy_brick(int x, int y)
3311 {
3312   int i, found;
3313   
3314   found = -1;
3315   
3316   for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++)
3317     {
3318       if (!bouncy_bricks[i].alive)
3319         found = i;
3320     }
3321   
3322   if (found != -1)
3323     {
3324       bouncy_bricks[found].alive = YES;
3325       bouncy_bricks[found].x = x;
3326       bouncy_bricks[found].y = y;
3327       bouncy_bricks[found].offset = 0;
3328       bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED;
3329       bouncy_bricks[found].shape = shape(x, y, 0);
3330     }
3331 }
3332
3333
3334 /* Add a bad guy: */
3335
3336 void add_bad_guy(int x, int y, int kind)
3337 {
3338   int i, found;
3339   
3340   found = -1;
3341   
3342   for (i = 0; i < NUM_BAD_GUYS && found == -1; i++)
3343     {
3344       if (!bad_guys[i].alive)
3345         found = i;
3346     }
3347   
3348   if (found != -1)
3349     {
3350       bad_guys[found].alive = YES;
3351       bad_guys[found].mode = NORMAL;
3352       bad_guys[found].dying = NO;
3353       bad_guys[found].timer = 0;
3354       bad_guys[found].kind = kind;
3355       bad_guys[found].x = x;
3356       bad_guys[found].y = y;
3357       bad_guys[found].xm = 0;
3358       bad_guys[found].ym = 0;
3359       bad_guys[found].dir = LEFT;
3360       bad_guys[found].seen = NO;
3361     }
3362 }
3363
3364
3365 /* Add score: */
3366
3367 void add_score(int x, int y, int s)
3368 {
3369   int i, found;
3370   
3371   
3372   /* Add the score: */
3373   
3374   score = score + s;
3375   
3376   
3377   /* Add a floating score thing to the game: */
3378   
3379   found = -1;
3380   
3381   for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++)
3382     {
3383       if (!floating_scores[i].alive)
3384         found = i;
3385     }
3386   
3387   
3388   if (found != -1)
3389     {
3390       floating_scores[found].alive = YES;
3391       floating_scores[found].x = x;
3392       floating_scores[found].y = y - 16;
3393       floating_scores[found].timer = 8;
3394       floating_scores[found].value = s;
3395     }
3396 }
3397
3398
3399 /* Try to bump a bad guy from below: */
3400
3401 void trybumpbadguy(int x, int y, int sx)
3402 {
3403   int i;
3404   
3405   
3406   /* Bad guys: */
3407   
3408   for (i = 0; i < NUM_BAD_GUYS; i++)
3409     {
3410       if (bad_guys[i].alive &&
3411           bad_guys[i].x >= x + sx - 32 && bad_guys[i].x <= x + sx + 32 &&
3412           bad_guys[i].y >= y - 16 && bad_guys[i].y <= y + 16)
3413         {
3414           if (bad_guys[i].kind == BAD_BSOD ||
3415               bad_guys[i].kind == BAD_LAPTOP)
3416             {
3417               bad_guys[i].dying = FALLING;
3418               bad_guys[i].ym = -8;
3419               play_sound(sounds[SND_FALL]);
3420             }
3421         }
3422     }
3423   
3424   
3425   /* Upgrades: */
3426   
3427   for (i = 0; i < NUM_UPGRADES; i++)
3428     {
3429       if (upgrades[i].alive && upgrades[i].height == 32 &&
3430           upgrades[i].x >= x + sx - 32 && upgrades[i].x <= x + sx + 32 &&
3431           upgrades[i].y >= y - 16 && upgrades[i].y <= y + 16)
3432         {
3433           upgrades[i].xm = -upgrades[i].xm;
3434           upgrades[i].ym = -8;
3435           play_sound(sounds[SND_BUMP_UPGRADE]);
3436         }
3437     }
3438 }
3439
3440
3441 /* Add an upgrade: */
3442
3443 void add_upgrade(int x, int y, int kind)
3444 {
3445   int i, found;
3446   
3447   found = -1;
3448   
3449   for (i = 0; i < NUM_UPGRADES && found == -1; i++)
3450     {
3451       if (!upgrades[i].alive)
3452         found = i;
3453     }
3454
3455   if (found != -1)
3456     {
3457       upgrades[found].alive = YES;
3458       upgrades[found].kind = kind;
3459       upgrades[found].x = x;
3460       upgrades[found].y = y;
3461       upgrades[found].xm = 4;
3462       upgrades[found].ym = -4;
3463       upgrades[found].height = 0;
3464     }
3465 }
3466
3467
3468 /* Kill tux! */
3469
3470 void killtux(int mode)
3471 {
3472   tux_ym = -16;
3473  
3474   play_sound(sounds[SND_HURT]);
3475  
3476   if (tux_dir == RIGHT)
3477     tux_xm = -8;
3478   else if (tux_dir == LEFT)
3479     tux_xm = 8;
3480   
3481   if (mode == SHRINK && tux_size == BIG)
3482     {
3483       if (tux_got_coffee)
3484         tux_got_coffee = NO;
3485
3486       tux_size = SMALL;
3487       
3488       tux_safe = TUX_SAFE_TIME;
3489     }
3490   else
3491     {
3492       tux_dying = 1;
3493     }
3494 }
3495
3496
3497 /* Add a bullet: */
3498
3499 void add_bullet(int x, int y, int dir, int xm)
3500 {
3501   int i, found;
3502   
3503   found = -1;
3504   
3505   for (i = 0; i < NUM_BULLETS && found == -1; i++)
3506     {
3507       if (!bullets[i].alive)
3508         found = i;
3509     }
3510
3511   if (found != -1)
3512     {
3513       bullets[found].alive = YES;
3514
3515       if (dir == RIGHT)
3516         {
3517           bullets[found].x = x + 32;
3518           bullets[found].xm = BULLET_XM + xm;
3519         }
3520       else
3521         {
3522           bullets[found].x = x;
3523           bullets[found].xm = -BULLET_XM + xm;
3524         }
3525       
3526       bullets[found].y = y;
3527       bullets[found].ym = BULLET_STARTING_YM;
3528       
3529       play_sound(sounds[SND_SHOOT]);
3530     }
3531 }
3532
3533
3534 void drawendscreen(void)
3535 {
3536   char str[80];
3537   
3538   clearscreen(0, 0, 0);
3539
3540   drawcenteredtext("GAMEOVER", 200, letters_red, NO_UPDATE);
3541
3542   sprintf(str, "SCORE: %d", score);
3543   drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
3544
3545   sprintf(str, "DISTROS: %d", distros);
3546   drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
3547
3548   SDL_Flip(screen);
3549   SDL_Delay(2000);
3550 }
3551
3552 void drawresultscreen(void)
3553 {
3554   char str[80];
3555   
3556   clearscreen(0, 0, 0);
3557
3558   drawcenteredtext("Result:", 200, letters_red, NO_UPDATE);
3559
3560   sprintf(str, "SCORE: %d", score);
3561   drawcenteredtext(str, 224, letters_gold, NO_UPDATE);
3562
3563   sprintf(str, "DISTROS: %d", distros);
3564   drawcenteredtext(str, 256, letters_blue, NO_UPDATE);
3565
3566   SDL_Flip(screen);
3567   SDL_Delay(2000);
3568 }
3569