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