f1d8c66356d16e0c134114ed93bad2b310fffebe
[supertux.git] / src / gameloop.cpp
1 /*
2   gameloop.c
3   
4   Super Tux - Game Loop!
5   
6   by Bill Kendrick & Tobias Glaesser
7   bill@newbreedsoftware.com
8   http://www.newbreedsoftware.com/supertux/
9   
10   April 11, 2000 - March 15, 2004
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <math.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <time.h>
20 #include <SDL.h>
21
22 #ifndef WIN32
23 #include <sys/types.h>
24 #include <ctype.h>
25 #endif
26
27 #include "defines.h"
28 #include "globals.h"
29 #include "gameloop.h"
30 #include "screen.h"
31 #include "setup.h"
32 #include "high_scores.h"
33 #include "menu.h"
34 #include "badguy.h"
35 #include "world.h"
36 #include "special.h"
37 #include "player.h"
38 #include "level.h"
39 #include "scene.h"
40 #include "collision.h"
41
42 /* extern variables */
43
44 st_level current_level;
45 int game_started = false;
46
47 /* Local variables: */
48
49 static texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
50 static texture_type img_cloud[2][4];
51 static SDL_Event event;
52 static SDLKey key;
53 static char level_subset[100];
54 static float fps_fps;
55 static int st_gl_mode;
56 static unsigned int last_update_time;
57 static unsigned int update_time;
58 static int pause_menu_frame;
59 static int debug_fps;
60
61 /* Local function prototypes: */
62
63 void levelintro(void);
64 void loadshared(void);
65 void unloadshared(void);
66 void drawstatus(void);
67 void drawendscreen(void);
68 void drawresultscreen(void);
69
70 void levelintro(void)
71 {
72   char str[60];
73   /* Level Intro: */
74   clearscreen(0, 0, 0);
75
76   sprintf(str, "LEVEL %d", level);
77   text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
78
79   sprintf(str, "%s", current_level.name.c_str());
80   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
81
82   sprintf(str, "TUX x %d", tux.lives);
83   text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
84
85   flipscreen();
86
87   SDL_Delay(1000);
88 }
89
90 /* Reset Timers */
91 void start_timers(void)
92 {
93   timer_start(&time_left,current_level.time_left*1000);
94   st_pause_ticks_init();
95   update_time = st_get_ticks();
96 }
97
98 void activate_bad_guys(void)
99 {
100   int x,y;
101
102   /* Activate bad guys: */
103
104   for (y = 0; y < 15; y++)
105     {
106       for (x = 0; x < current_level.width; x++)
107         {
108           if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
109             {
110               add_bad_guy(x * 32, y * 32, static_cast<BadGuyKind>(current_level.tiles[y][x] - '0'));
111               current_level.tiles[y][x] = '.';
112             }
113         }
114     }
115
116 }
117
118 /* --- GAME EVENT! --- */
119
120 void game_event(void)
121 {
122   while (SDL_PollEvent(&event))
123     {
124       switch(event.type)
125         {
126         case SDL_QUIT:        /* Quit event - quit: */
127           quit = 1;
128           break;
129         case SDL_KEYDOWN:     /* A keypress! */
130           key = event.key.keysym.sym;
131
132           /* Check for menu-events, if the menu is shown */
133           if(show_menu)
134             menu_event(&event.key.keysym);
135
136           if(tux.key_event(key,DOWN))
137             break;
138
139           switch(key)
140             {
141             case SDLK_ESCAPE:    /* Escape: Open/Close the menu: */
142               if(!game_pause)
143                 {
144                   if(st_gl_mode == ST_GL_TEST)
145                     quit = 1;
146                   else if(show_menu)
147                     {
148                       Menu::set_current(game_menu);
149                       show_menu = 0;
150                       st_pause_ticks_stop();
151                     }
152                   else
153                     {
154                       Menu::set_current(game_menu);
155                       show_menu = 1;
156                       st_pause_ticks_start();
157                     }
158                 }
159               break;
160             default:
161               break;
162             }
163           break;
164         case SDL_KEYUP:      /* A keyrelease! */
165           key = event.key.keysym.sym;
166
167           if(tux.key_event(key, UP))
168             break;
169
170           switch(key)
171             {
172             case SDLK_p:
173               if(!show_menu)
174                 {
175                   if(game_pause)
176                     {
177                       game_pause = 0;
178                       st_pause_ticks_stop();
179                     }
180                   else
181                     {
182                       game_pause = 1;
183                       st_pause_ticks_start();
184                     }
185                 }
186               break;
187             case SDLK_TAB:
188               if(debug_mode)
189                 {
190                   tux.size = !tux.size;
191                   if(tux.size == BIG)
192                     {
193                       tux.base.height = 64;
194                     }
195                   else
196                     tux.base.height = 32;
197                 }
198               break;
199             case SDLK_END:
200               if(debug_mode)
201                 distros += 50;
202               break;
203             case SDLK_SPACE:
204               if(debug_mode)
205                 next_level = 1;
206               break;
207             case SDLK_DELETE:
208               if(debug_mode)
209                 tux.got_coffee = 1;
210               break;
211             case SDLK_INSERT:
212               if(debug_mode)
213                 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
214               break;
215             case SDLK_l:
216               if(debug_mode)
217                 --tux.lives;
218               break;
219             case SDLK_s:
220               if(debug_mode)
221                 score += 1000;
222             case SDLK_f:
223               if(debug_fps)
224                 debug_fps = false;
225               else
226                 debug_fps = true;
227               break;          
228             default:
229               break;
230             }
231           break;
232
233         case SDL_JOYAXISMOTION:
234           switch(event.jaxis.axis)
235             {
236             case JOY_X:
237               if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
238                 {
239                   tux.input_.left  = DOWN;
240                   tux.input_.right = UP;
241                 }
242               else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
243                 {
244                   tux.input_.left  = UP;
245                   tux.input_.right = DOWN;
246                 }
247               else
248                 {
249                   tux.input_.left  = DOWN;
250                   tux.input_.right = DOWN;
251                 }
252               break;
253             case JOY_Y:
254               if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
255                 tux.input_.down = DOWN;
256               else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
257                 tux.input_.down = UP;
258               else
259                 tux.input_.down = UP;
260
261               /* Handle joystick for the menu */
262               if(show_menu)
263                 {
264                   if(tux.input_.down == DOWN)
265                     menuaction = MENU_ACTION_DOWN;
266                   else
267                     menuaction = MENU_ACTION_UP;
268                 }
269               break;
270             default:
271               break;
272             }
273           break;
274         case SDL_JOYBUTTONDOWN:
275           if (event.jbutton.button == JOY_A)
276             tux.input_.up = DOWN;
277           else if (event.jbutton.button == JOY_B)
278             tux.input_.fire = DOWN;
279           break;
280         case SDL_JOYBUTTONUP:
281           if (event.jbutton.button == JOY_A)
282             tux.input_.up = UP;
283           else if (event.jbutton.button == JOY_B)
284             tux.input_.fire = UP;
285
286           if(show_menu)
287             menuaction = MENU_ACTION_HIT;
288           break;
289
290         default:
291           break;
292
293         }  /* switch */
294
295     } /* while */
296 }
297
298 /* --- GAME ACTION! --- */
299
300 int game_action(void)
301 {
302   unsigned int i;
303
304   /* (tux_dying || next_level) */
305   if (tux.dying || next_level)
306     {
307       /* Tux either died, or reached the end of a level! */
308
309       halt_music();
310
311
312       if (next_level)
313         {
314           /* End of a level! */
315           level++;
316           next_level = 0;
317           if(st_gl_mode != ST_GL_TEST)
318             {
319               drawresultscreen();
320             }
321           else
322             {
323               level_free_gfx();
324               level_free(&current_level);
325               level_free_song();
326               unloadshared();
327               arrays_free();
328               return(0);
329             }
330           tux.level_begin();
331         }
332       else
333         {
334           tux.is_dying();
335
336           /* No more lives!? */
337
338           if (tux.lives < 0)
339             {
340               if(st_gl_mode != ST_GL_TEST)
341                 drawendscreen();
342
343               if(st_gl_mode != ST_GL_TEST)
344                 {
345                   if (score > hs_score)
346                     save_hs(score);
347                 }
348               level_free_gfx();
349               level_free(&current_level);
350               level_free_song();
351               unloadshared();
352               arrays_free();
353               return(0);
354             } /* if (lives < 0) */
355         }
356
357       /* Either way, (re-)load the (next) level... */
358
359       tux.level_begin();
360       set_defaults();
361       level_free(&current_level);
362
363       if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
364         {
365           if(level_load(&current_level, level_subset) != 0)
366             return 0;
367         }
368       else
369         {
370           if(level_load(&current_level,level_subset,level) != 0)
371             return 0;
372         }
373
374       arrays_free();
375       arrays_init();
376       activate_bad_guys();
377       level_free_gfx();
378       level_load_gfx(&current_level);
379       level_free_song();
380       level_load_song(&current_level);
381       if(st_gl_mode != ST_GL_TEST)
382         levelintro();
383       start_timers();
384       /* Play music: */
385       play_current_music();
386     }
387
388   tux.action();
389
390   /* Handle bouncy distros: */
391   for (i = 0; i < bouncy_distros.size(); i++)
392     {
393       bouncy_distro_action(&bouncy_distros[i]);
394     }
395
396
397   /* Handle broken bricks: */
398   for (i = 0; i < broken_bricks.size(); i++)
399     {
400       broken_brick_action(&broken_bricks[i]);
401     }
402
403
404   /* Handle distro counting: */
405
406   if (counting_distros)
407     {
408       distro_counter--;
409
410       if (distro_counter <= 0)
411         counting_distros = -1;
412     }
413
414
415   /* Handle bouncy bricks: */
416
417   for (i = 0; i < bouncy_bricks.size(); i++)
418     {
419       bouncy_brick_action(&bouncy_bricks[i]);
420     }
421
422
423   /* Handle floating scores: */
424
425   for (i = 0; i < floating_scores.size(); i++)
426     {
427       floating_score_action(&floating_scores[i]);
428     }
429
430
431   /* Handle bullets: */
432
433   for (i = 0; i < bullets.size(); ++i)
434     {
435       bullet_action(&bullets[i]);
436     }
437
438   /* Handle upgrades: */
439
440   for (i = 0; i < upgrades.size(); i++)
441     {
442       upgrade_action(&upgrades[i]);
443     }
444
445
446   /* Handle bad guys: */
447
448   for (i = 0; i < bad_guys.size(); i++)
449     {
450       bad_guys[i].action();
451     }
452
453   /* Handle all possible collisions. */
454   collision_handler();
455
456   return -1;
457 }
458
459 /* --- GAME DRAW! --- */
460
461 void game_draw(void)
462 {
463   /* Draw screen: */
464   if (tux.dying && (global_frame_counter % 4) == 0)
465     clearscreen(255, 255, 255);
466   else if(timer_check(&super_bkgd_timer))
467     texture_draw(&img_super_bkgd, 0, 0);
468   else
469     {
470       /* Draw the real background */
471       if(current_level.bkgd_image[0] != '\0')
472         {
473           int s = (int)scroll_x / 30;
474           texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
475           texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
476         }
477       else
478         {
479           clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
480         }
481     }
482
483   // Draw background:
484   for (int y = 0; y < 15; ++y)
485     {
486       for (int x = 0; x < 21; ++x)
487         {
488           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
489                     current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
490         }
491     }
492
493   for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
494     bouncy_brick_draw(&bouncy_bricks[i]);
495
496   for (unsigned int i = 0; i < bad_guys.size(); ++i)
497     bad_guys[i].draw();
498
499   tux.draw();
500
501   for (unsigned int i = 0; i < bullets.size(); ++i)
502     bullet_draw(&bullets[i]);
503
504   for (unsigned int i = 0; i < floating_scores.size(); ++i)
505     floating_score_draw(&floating_scores[i]);
506
507   for (unsigned int i = 0; i < upgrades.size(); ++i)
508     upgrade_draw(&upgrades[i]);
509
510   for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
511       bouncy_distro_draw(&bouncy_distros[i]);
512
513   for (unsigned int i = 0; i < broken_bricks.size(); ++i)
514     broken_brick_draw(&broken_bricks[i]);
515
516   drawstatus();
517
518   if(game_pause)
519     {
520       int x = screen->h / 20;
521       for(int i = 0; i < x; ++i)
522         {
523           fillrect(i % 2 ? (pause_menu_frame * i)%screen->w : -((pause_menu_frame * i)%screen->w) ,(i*20+pause_menu_frame)%screen->h,screen->w,10,20,20,20, rand() % 20 + 1);
524         }
525       fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
526       text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
527     }
528
529   if(show_menu)
530     menu_process_current();
531
532   /* (Update it all!) */
533
534   updatescreen();
535
536
537 }
538
539 /* --- GAME LOOP! --- */
540
541 int gameloop(const char * subset, int levelnb, int mode)
542 {
543   int fps_cnt, jump, done;
544   timer_type fps_timer, frame_timer;
545   timer_init(&fps_timer, true);
546   timer_init(&frame_timer, true);
547
548   game_started = true;
549
550   st_gl_mode = mode;
551   level = levelnb;
552
553   /* Init the game: */
554   arrays_init();
555   set_defaults();
556
557   strcpy(level_subset,subset);
558
559   if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
560     {
561       if (level_load(&current_level, level_subset))
562         exit(1);
563     }
564   else
565     {
566       if(level_load(&current_level, level_subset, level) != 0)
567         exit(1);
568     }
569
570   level_load_gfx(&current_level);
571   activate_bad_guys();
572   level_load_song(&current_level);
573
574   tux.init();
575
576   if(st_gl_mode != ST_GL_TEST)
577     load_hs();
578
579   loadshared();
580
581   if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
582     levelintro();
583
584   timer_init(&time_left,true);
585   start_timers();
586
587   if(st_gl_mode == ST_GL_LOAD_GAME)
588     loadgame(levelnb);
589
590
591   /* --- MAIN GAME LOOP!!! --- */
592
593   jump = false;
594   done = 0;
595   quit = 0;
596   global_frame_counter = 0;
597   game_pause = 0;
598   timer_init(&fps_timer,true);
599   timer_init(&frame_timer,true);
600   fps_cnt = 0;
601
602   /* Clear screen: */
603
604   clearscreen(0, 0, 0);
605   updatescreen();
606
607   /* Play music: */
608   play_current_music();
609
610
611   while (SDL_PollEvent(&event))
612     {}
613
614   game_draw();
615   do
616     {
617       jump = false;
618
619       /* Calculate the movement-factor */
620       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
621       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
622         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
623       
624       if(!timer_check(&frame_timer))
625         {
626           timer_start(&frame_timer,25);
627           ++global_frame_counter;
628         }
629
630       /* Handle events: */
631
632       tux.input_.old_fire = tux.input_.fire;
633
634       game_event();
635
636       if(show_menu)
637         {
638           if(current_menu == game_menu)
639             {
640               switch (game_menu->check())
641                 {
642                 case 2:
643                   st_pause_ticks_stop();
644                   break;
645                 case 3:
646                   update_load_save_game_menu(save_game_menu, false);
647                   break;
648                 case 4:
649                   update_load_save_game_menu(load_game_menu, true);
650                   break;
651                 case 7:
652                   st_pause_ticks_stop();
653                   done = 1;
654                   break;
655                 }
656             }
657           else if(current_menu == options_menu)
658             {
659               process_options_menu();
660             }
661           else if(current_menu == save_game_menu )
662             {
663               process_save_load_game_menu(true);
664             }
665           else if(current_menu == load_game_menu )
666             {
667               process_save_load_game_menu(false);
668             }
669         }
670
671
672       /* Handle actions: */
673
674       if(!game_pause && !show_menu)
675         {
676           /*float z = frame_ratio;
677             frame_ratio = 1;
678             while(z >= 1)
679             {*/
680           if (game_action() == 0)
681             {
682               /* == 0: no more lives */
683               /* == -1: continues */
684               return 0;
685             }
686           /*  --z;
687               }*/
688         }
689       else
690         {
691           ++pause_menu_frame;
692           SDL_Delay(50);
693         }
694
695       if(debug_mode && debug_fps == true)
696         SDL_Delay(60);
697
698       /*Draw the current scene to the screen */
699       /*If the machine running the game is too slow
700         skip the drawing of the frame (so the calculations are more precise and
701         the FPS aren't affected).*/
702       /*if( ! fps_fps < 50.0 )
703         game_draw();
704         else
705         jump = true;*/ /*FIXME: Implement this tweak right.*/
706       game_draw();
707
708       /* Time stops in pause mode */
709       if(game_pause || show_menu )
710         {
711           continue;
712         }
713
714       /* Set the time of the last update and the time of the current update */
715       last_update_time = update_time;
716       update_time = st_get_ticks();
717
718
719       /* Pause till next frame, if the machine running the game is too fast: */
720       /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
721          the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
722       if(last_update_time >= update_time - 12 && !jump)
723         SDL_Delay(10);
724       /*if((update_time - last_update_time) < 10)
725         SDL_Delay((11 - (update_time - last_update_time))/2);*/
726
727
728
729       /* Handle time: */
730
731       if (timer_check(&time_left))
732         {
733           /* are we low on time ? */
734           if ((timer_get_left(&time_left) < TIME_WARNING)
735               && (get_current_music() != HURRYUP_MUSIC))     /* play the fast music */
736             {
737               set_current_music(HURRYUP_MUSIC);
738               play_current_music();
739             }
740
741         }
742       else
743         tux.kill(KILL);
744
745
746       /* Calculate frames per second */
747       if(show_fps)
748         {
749           ++fps_cnt;
750           fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
751
752           if(!timer_check(&fps_timer))
753             {
754               timer_start(&fps_timer,1000);
755               fps_cnt = 0;
756             }
757         }
758
759     }
760   while (!done && !quit);
761
762   halt_music();
763
764   level_free_gfx();
765   level_free(&current_level);
766   level_free_song();
767   unloadshared();
768   arrays_free();
769
770   game_started = false;
771
772   return(quit);
773 }
774
775
776 /* Load graphics/sounds shared between all levels: */
777
778 void loadshared(void)
779 {
780   int i;
781
782   /* Tuxes: */
783   texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
784   texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
785   texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
786
787   texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
788   texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
789   texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
790
791   texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
792   texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
793   texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
794
795   texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
796   texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
797   texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
798
799
800   texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
801                USE_ALPHA);
802
803   texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
804                USE_ALPHA);
805
806   texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
807                USE_ALPHA);
808
809   texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
810                USE_ALPHA);
811
812   texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
813                USE_ALPHA);
814
815   texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
816                USE_ALPHA);
817
818   texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
819                USE_ALPHA);
820
821   texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
822
823   texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
824                USE_ALPHA);
825
826   texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
827                USE_ALPHA);
828
829   texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
830                USE_ALPHA);
831
832   texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
833
834   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
835                USE_ALPHA);
836
837   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
838                USE_ALPHA);
839
840   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
841                USE_ALPHA);
842
843   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
844                USE_ALPHA);
845
846   texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
847                USE_ALPHA);
848
849   texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
850                USE_ALPHA);
851
852   texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
853                USE_ALPHA);
854
855   texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
856
857   texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
858                USE_ALPHA);
859
860   texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
861                USE_ALPHA);
862
863   texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
864                USE_ALPHA);
865
866   texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
867
868   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
869                USE_ALPHA);
870
871   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
872                USE_ALPHA);
873
874   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
875                USE_ALPHA);
876
877   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
878                USE_ALPHA);
879
880
881   texture_load(&ducktux_right, datadir +
882                "/images/shared/ducktux-right.png",
883                USE_ALPHA);
884
885   texture_load(&ducktux_left, datadir +
886                "/images/shared/ducktux-left.png",
887                USE_ALPHA);
888
889   texture_load(&skidtux_right, datadir +
890                "/images/shared/skidtux-right.png",
891                USE_ALPHA);
892
893   texture_load(&skidtux_left, datadir +
894                "/images/shared/skidtux-left.png",
895                USE_ALPHA);
896
897   texture_load(&duckfiretux_right, datadir +
898                "/images/shared/duckfiretux-right.png",
899                USE_ALPHA);
900
901   texture_load(&duckfiretux_left, datadir +
902                "/images/shared/duckfiretux-left.png",
903                USE_ALPHA);
904
905   texture_load(&skidfiretux_right, datadir +
906                "/images/shared/skidfiretux-right.png",
907                USE_ALPHA);
908
909   texture_load(&skidfiretux_left, datadir +
910                "/images/shared/skidfiretux-left.png",
911                USE_ALPHA);
912
913
914   /* Boxes: */
915
916   texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
917                IGNORE_ALPHA);
918   texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
919                IGNORE_ALPHA);
920
921
922   /* Water: */
923
924
925   texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
926
927   texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
928                USE_ALPHA);
929
930   texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
931                USE_ALPHA);
932
933   texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
934                USE_ALPHA);
935
936
937   /* Pole: */
938
939   texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
940   texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
941                USE_ALPHA);
942
943
944   /* Flag: */
945
946   texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
947                USE_ALPHA);
948   texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
949                USE_ALPHA);
950
951
952   /* Cloud: */
953
954   texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
955                USE_ALPHA);
956
957   texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
958                USE_ALPHA);
959
960   texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
961                USE_ALPHA);
962
963   texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
964                USE_ALPHA);
965
966
967   texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
968                USE_ALPHA);
969
970   texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
971                USE_ALPHA);
972
973   texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
974                USE_ALPHA);
975
976   texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
977                USE_ALPHA);
978
979
980   /* Bad guys: */
981
982   /* (BSOD) */
983
984   texture_load(&img_bsod_left[0], datadir +
985                "/images/shared/bsod-left-0.png",
986                USE_ALPHA);
987
988   texture_load(&img_bsod_left[1], datadir +
989                "/images/shared/bsod-left-1.png",
990                USE_ALPHA);
991
992   texture_load(&img_bsod_left[2], datadir +
993                "/images/shared/bsod-left-2.png",
994                USE_ALPHA);
995
996   texture_load(&img_bsod_left[3], datadir +
997                "/images/shared/bsod-left-3.png",
998                USE_ALPHA);
999
1000   texture_load(&img_bsod_right[0], datadir +
1001                "/images/shared/bsod-right-0.png",
1002                USE_ALPHA);
1003
1004   texture_load(&img_bsod_right[1], datadir +
1005                "/images/shared/bsod-right-1.png",
1006                USE_ALPHA);
1007
1008   texture_load(&img_bsod_right[2], datadir +
1009                "/images/shared/bsod-right-2.png",
1010                USE_ALPHA);
1011
1012   texture_load(&img_bsod_right[3], datadir +
1013                "/images/shared/bsod-right-3.png",
1014                USE_ALPHA);
1015
1016   texture_load(&img_bsod_squished_left, datadir +
1017                "/images/shared/bsod-squished-left.png",
1018                USE_ALPHA);
1019
1020   texture_load(&img_bsod_squished_right, datadir +
1021                "/images/shared/bsod-squished-right.png",
1022                USE_ALPHA);
1023
1024   texture_load(&img_bsod_falling_left, datadir +
1025                "/images/shared/bsod-falling-left.png",
1026                USE_ALPHA);
1027
1028   texture_load(&img_bsod_falling_right, datadir +
1029                "/images/shared/bsod-falling-right.png",
1030                USE_ALPHA);
1031
1032
1033   /* (Laptop) */
1034
1035   texture_load(&img_laptop_left[0], datadir +
1036                "/images/shared/laptop-left-0.png",
1037                USE_ALPHA);
1038
1039   texture_load(&img_laptop_left[1], datadir +
1040                "/images/shared/laptop-left-1.png",
1041                USE_ALPHA);
1042
1043   texture_load(&img_laptop_left[2], datadir +
1044                "/images/shared/laptop-left-2.png",
1045                USE_ALPHA);
1046
1047   texture_load(&img_laptop_right[0], datadir +
1048                "/images/shared/laptop-right-0.png",
1049                USE_ALPHA);
1050
1051   texture_load(&img_laptop_right[1], datadir +
1052                "/images/shared/laptop-right-1.png",
1053                USE_ALPHA);
1054
1055   texture_load(&img_laptop_right[2], datadir +
1056                "/images/shared/laptop-right-2.png",
1057                USE_ALPHA);
1058
1059   texture_load(&img_laptop_flat_left, datadir +
1060                "/images/shared/laptop-flat-left.png",
1061                USE_ALPHA);
1062
1063   texture_load(&img_laptop_flat_right, datadir +
1064                "/images/shared/laptop-flat-right.png",
1065                USE_ALPHA);
1066
1067   texture_load(&img_laptop_falling_left, datadir +
1068                "/images/shared/laptop-falling-left.png",
1069                USE_ALPHA);
1070
1071   texture_load(&img_laptop_falling_right, datadir +
1072                "/images/shared/laptop-falling-right.png",
1073                USE_ALPHA);
1074
1075
1076   /* (Money) */
1077
1078   texture_load(&img_money_left[0], datadir +
1079                "/images/shared/bag-left-0.png",
1080                USE_ALPHA);
1081
1082   texture_load(&img_money_left[1], datadir +
1083                "/images/shared/bag-left-1.png",
1084                USE_ALPHA);
1085
1086   texture_load(&img_money_right[0], datadir +
1087                "/images/shared/bag-right-0.png",
1088                USE_ALPHA);
1089
1090   texture_load(&img_money_right[1], datadir +
1091                "/images/shared/bag-right-1.png",
1092                USE_ALPHA);
1093
1094
1095
1096   /* Upgrades: */
1097
1098   texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1099   texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1100
1101
1102   /* Weapons: */
1103
1104   texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1105
1106   texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1107                USE_ALPHA);
1108
1109
1110
1111   /* Distros: */
1112
1113   texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1114                USE_ALPHA);
1115
1116   texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1117                USE_ALPHA);
1118
1119   texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1120                USE_ALPHA);
1121
1122   texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1123                USE_ALPHA);
1124
1125
1126   /* Tux life: */
1127
1128   texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1129                USE_ALPHA);
1130
1131   /* Herring: */
1132
1133   texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1134                USE_ALPHA);
1135
1136
1137   /* Super background: */
1138
1139   texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1140                IGNORE_ALPHA);
1141
1142
1143   /* Sound effects: */
1144
1145   /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1146                     // initialize sounds[i] with the correct pointer's value:
1147                     // NULL or something else. And it will be dangerous to
1148                     // play with not-initialized pointers.
1149                     // This is also true with if (use_music)
1150                     Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1151   */
1152   for (i = 0; i < NUM_SOUNDS; i++)
1153     sounds[i] = load_sound(datadir + soundfilenames[i]);
1154
1155   /* Herring song */
1156   herring_song = load_song(datadir + "/music/SALCON.MOD");
1157 }
1158
1159
1160 /* Free shared data: */
1161
1162 void unloadshared(void)
1163 {
1164   int i;
1165
1166   for (i = 0; i < 3; i++)
1167     {
1168       texture_free(&tux_right[i]);
1169       texture_free(&tux_left[i]);
1170       texture_free(&bigtux_right[i]);
1171       texture_free(&bigtux_left[i]);
1172     }
1173
1174   texture_free(&bigtux_right_jump);
1175   texture_free(&bigtux_left_jump);
1176
1177   for (i = 0; i < 2; i++)
1178     {
1179       texture_free(&cape_right[i]);
1180       texture_free(&cape_left[i]);
1181       texture_free(&bigcape_right[i]);
1182       texture_free(&bigcape_left[i]);
1183     }
1184
1185   texture_free(&ducktux_left);
1186   texture_free(&ducktux_right);
1187
1188   texture_free(&skidtux_left);
1189   texture_free(&skidtux_right);
1190
1191   for (i = 0; i < 4; i++)
1192     {
1193       texture_free(&img_bsod_left[i]);
1194       texture_free(&img_bsod_right[i]);
1195     }
1196
1197   texture_free(&img_bsod_squished_left);
1198   texture_free(&img_bsod_squished_right);
1199
1200   texture_free(&img_bsod_falling_left);
1201   texture_free(&img_bsod_falling_right);
1202
1203   for (i = 0; i < 3; i++)
1204     {
1205       texture_free(&img_laptop_left[i]);
1206       texture_free(&img_laptop_right[i]);
1207     }
1208
1209   texture_free(&img_laptop_flat_left);
1210   texture_free(&img_laptop_flat_right);
1211
1212   texture_free(&img_laptop_falling_left);
1213   texture_free(&img_laptop_falling_right);
1214
1215   for (i = 0; i < 2; i++)
1216     {
1217       texture_free(&img_money_left[i]);
1218       texture_free(&img_money_right[i]);
1219     }
1220
1221   texture_free(&img_box_full);
1222   texture_free(&img_box_empty);
1223
1224   texture_free(&img_water);
1225   for (i = 0; i < 3; i++)
1226     texture_free(&img_waves[i]);
1227
1228   texture_free(&img_pole);
1229   texture_free(&img_poletop);
1230
1231   for (i = 0; i < 2; i++)
1232     texture_free(&img_flag[i]);
1233
1234   texture_free(&img_mints);
1235   texture_free(&img_coffee);
1236
1237   for (i = 0; i < 4; i++)
1238     {
1239       texture_free(&img_distro[i]);
1240       texture_free(&img_cloud[0][i]);
1241       texture_free(&img_cloud[1][i]);
1242     }
1243
1244   texture_free(&img_golden_herring);
1245
1246   for (i = 0; i < NUM_SOUNDS; i++)
1247     free_chunk(sounds[i]);
1248
1249   /* free the herring song */
1250   free_music( herring_song );
1251 }
1252
1253
1254 /* Draw a tile on the screen: */
1255
1256 void drawshape(float x, float y, unsigned char c)
1257 {
1258   int z;
1259
1260   if (c == 'X' || c == 'x')
1261     texture_draw(&img_brick[0], x, y);
1262   else if (c == 'Y' || c == 'y')
1263     texture_draw(&img_brick[1], x, y);
1264   else if (c == 'A' || c =='B' || c == '!')
1265     texture_draw(&img_box_full, x, y);
1266   else if (c == 'a')
1267     texture_draw(&img_box_empty, x, y);
1268   else if (c >= 'C' && c <= 'F')
1269     texture_draw(&img_cloud[0][c - 'C'], x, y);
1270   else if (c >= 'c' && c <= 'f')
1271     texture_draw(&img_cloud[1][c - 'c'], x, y);
1272   else if (c >= 'G' && c <= 'J')
1273     texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1274   else if (c >= 'g' && c <= 'j')
1275     texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1276   else if (c == '#')
1277     texture_draw(&img_solid[0], x, y);
1278   else if (c == '[')
1279     texture_draw(&img_solid[1], x, y);
1280   else if (c == '=')
1281     texture_draw(&img_solid[2], x, y);
1282   else if (c == ']')
1283     texture_draw(&img_solid[3], x, y);
1284   else if (c == '$')
1285     {
1286       z = (global_frame_counter / 2) % 6;
1287
1288       if (z < 4)
1289         texture_draw(&img_distro[z], x, y);
1290       else if (z == 4)
1291         texture_draw(&img_distro[2], x, y);
1292       else if (z == 5)
1293         texture_draw(&img_distro[1], x, y);
1294     }
1295   else if (c == '^')
1296     {
1297       z = (global_frame_counter / 3) % 3;
1298
1299       texture_draw(&img_waves[z], x, y);
1300     }
1301   else if (c == '*')
1302     texture_draw(&img_poletop, x, y);
1303   else if (c == '|')
1304     {
1305       texture_draw(&img_pole, x, y);
1306
1307     }
1308   else if (c == '\\')
1309     {
1310       z = (global_frame_counter / 3) % 2;
1311
1312       texture_draw(&img_flag[z], x + 16, y);
1313     }
1314   else if (c == '&')
1315     texture_draw(&img_water, x, y);
1316 }
1317
1318
1319 /* What shape is at some position? */
1320
1321 unsigned char shape(float x, float y)
1322 {
1323
1324   int xx, yy;
1325   unsigned char c;
1326
1327   yy = ((int)y / 32);
1328   xx = ((int)x / 32);
1329
1330   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1331     {
1332       c = current_level.tiles[yy][xx];
1333     }
1334   else
1335     c = '.';
1336
1337   return(c);
1338 }
1339
1340 /* Is is ground? */
1341
1342
1343 bool issolid(float x, float y)
1344 {
1345   return (isbrick(x, y) ||
1346           isice(x, y) ||
1347           (shape(x, y) == '[') ||
1348           (shape(x, y) == '=') ||
1349           (shape(x, y) == ']') ||
1350           (shape(x, y) == 'A') ||
1351           (shape(x, y) == 'B') ||
1352           (shape(x, y) == '!') ||
1353           (shape(x, y) == 'a'));
1354 }
1355
1356 /* Is it a brick? */
1357
1358 bool isbrick(float x, float y)
1359 {
1360   return (shape(x, y) == 'X' ||
1361           shape(x, y) == 'x' ||
1362           shape(x, y) == 'Y' ||
1363           shape(x, y) == 'y');
1364 }
1365
1366
1367 /* Is it ice? */
1368
1369 bool isice(float x, float y)
1370 {
1371   return (shape(x, y) == '#');
1372 }
1373
1374 /* Is it a full box? */
1375
1376 bool isfullbox(float x, float y)
1377 {
1378   return (shape(x, y) == 'A' ||
1379           shape(x, y) == 'B' ||
1380           shape(x, y) == '!');
1381 }
1382
1383 /* Break a brick: */
1384
1385 void trybreakbrick(float x, float y)
1386 {
1387   if (isbrick(x, y))
1388     {
1389       if (shape(x, y) == 'x' || shape(x, y) == 'y')
1390         {
1391           /* Get a distro from it: */
1392
1393           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1394                             (int)(y / 32) * 32);
1395
1396           if (!counting_distros)
1397             {
1398               counting_distros = true;
1399               distro_counter = 50;
1400             }
1401
1402           if (distro_counter <= 0)
1403             level_change(&current_level,x, y, 'a');
1404
1405           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1406           score = score + SCORE_DISTRO;
1407           distros++;
1408         }
1409       else
1410         {
1411           /* Get rid of it: */
1412
1413           level_change(&current_level,x, y,'.');
1414         }
1415
1416
1417       /* Replace it with broken bits: */
1418
1419       add_broken_brick(((int)(x + 1) / 32) * 32,
1420                        (int)(y / 32) * 32);
1421
1422
1423       /* Get some score: */
1424
1425       play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1426       score = score + SCORE_BRICK;
1427     }
1428 }
1429
1430
1431 /* Bounce a brick: */
1432
1433 void bumpbrick(float x, float y)
1434 {
1435   add_bouncy_brick(((int)(x + 1) / 32) * 32,
1436                    (int)(y / 32) * 32);
1437
1438   play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1439
1440 }
1441
1442
1443 /* Empty a box: */
1444
1445 void tryemptybox(float x, float y, int col_side)
1446 {
1447   if (!isfullbox(x, y))
1448     return;
1449
1450   // according to the collision side, set the upgrade direction
1451
1452   if(col_side == LEFT)
1453     col_side = RIGHT;
1454   else
1455     col_side = LEFT;
1456
1457   switch(shape(x,y))
1458     {
1459     case 'A':      /* Box with a distro! */
1460       add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1461       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1462       score = score + SCORE_DISTRO;
1463       distros++;
1464       break;
1465     case 'B':      /* Add an upgrade! */
1466       if (tux.size == SMALL)     /* Tux is small, add mints! */
1467         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1468       else     /* Tux is big, add coffee: */
1469         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1470       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1471       break;
1472     case '!':     /* Add a golden herring */
1473       add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1474       break;
1475     default:
1476       break;
1477     }
1478
1479   /* Empty the box: */
1480   level_change(&current_level,x, y, 'a');
1481 }
1482
1483
1484 /* Try to grab a distro: */
1485
1486 void trygrabdistro(float x, float y, int bounciness)
1487 {
1488   if (shape(x, y) == '$')
1489     {
1490       level_change(&current_level,x, y, '.');
1491       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1492
1493       if (bounciness == BOUNCE)
1494         {
1495           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1496                             (int)(y / 32) * 32);
1497         }
1498
1499       score = score + SCORE_DISTRO;
1500       distros++;
1501     }
1502 }
1503
1504 /* Try to bump a bad guy from below: */
1505
1506 void trybumpbadguy(float x, float y)
1507 {
1508   unsigned int i;
1509
1510   /* Bad guys: */
1511   for (i = 0; i < bad_guys.size(); i++)
1512     {
1513       if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1514           bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1515         {
1516           if (bad_guys[i].kind == BAD_BSOD ||
1517               bad_guys[i].kind == BAD_LAPTOP)
1518             {
1519               bad_guys[i].dying = DYING_FALLING;
1520               bad_guys[i].base.ym = -8;
1521               play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1522             }
1523         }
1524     }
1525
1526
1527   /* Upgrades: */
1528   for (i = 0; i < upgrades.size(); i++)
1529     {
1530       if (upgrades[i].base.height == 32 &&
1531           upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1532           upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1533         {
1534           upgrades[i].base.xm = -upgrades[i].base.xm;
1535           upgrades[i].base.ym = -8;
1536           play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1537         }
1538     }
1539 }
1540
1541 /* (Status): */
1542 void drawstatus(void)
1543 {
1544   char str[60];
1545
1546   sprintf(str, "%d", score);
1547   text_draw(&white_text, "SCORE", 0, 0, 1);
1548   text_draw(&gold_text, str, 96, 0, 1);
1549
1550   if(st_gl_mode != ST_GL_TEST)
1551     {
1552       sprintf(str, "%d", hs_score);
1553       text_draw(&white_text, "HIGH", 0, 20, 1);
1554       text_draw(&gold_text, str, 96, 20, 1);
1555     }
1556   else
1557     {
1558       text_draw(&white_text,"Press ESC To Return",0,20,1);
1559     }
1560
1561   if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1562     {
1563       sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1564       text_draw(&white_text, "TIME", 224, 0, 1);
1565       text_draw(&gold_text, str, 304, 0, 1);
1566     }
1567
1568   sprintf(str, "%d", distros);
1569   text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1570   text_draw(&gold_text, str, 608, 0, 1);
1571
1572   text_draw(&white_text, "LIVES", screen->h, 20, 1);
1573
1574   if(show_fps)
1575     {
1576       sprintf(str, "%2.1f", fps_fps);
1577       text_draw(&white_text, "FPS", screen->h, 40, 1);
1578       text_draw(&gold_text, str, screen->h + 60, 40, 1);
1579     }
1580
1581   for(int i=0; i < tux.lives; ++i)
1582     {
1583       texture_draw(&tux_life,565+(18*i),20);
1584     }
1585 }
1586
1587
1588 void drawendscreen(void)
1589 {
1590   char str[80];
1591
1592   clearscreen(0, 0, 0);
1593
1594   text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1595
1596   sprintf(str, "SCORE: %d", score);
1597   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1598
1599   sprintf(str, "DISTROS: %d", distros);
1600   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1601
1602   flipscreen();
1603   SDL_Delay(2000);
1604 }
1605
1606 void drawresultscreen(void)
1607 {
1608   char str[80];
1609
1610   clearscreen(0, 0, 0);
1611
1612   text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1613
1614   sprintf(str, "SCORE: %d", score);
1615   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1616
1617   sprintf(str, "DISTROS: %d", distros);
1618   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1619
1620   flipscreen();
1621   SDL_Delay(2000);
1622 }
1623
1624 void savegame(int slot)
1625 {
1626   char savefile[1024];
1627   FILE* fi;
1628   unsigned int ui;
1629
1630   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1631
1632   fi = fopen(savefile, "wb");
1633
1634   if (fi == NULL)
1635     {
1636       fprintf(stderr, "Warning: I could not open the slot file ");
1637
1638     }
1639   else
1640     {
1641       fputs(level_subset, fi);
1642       fputs("\n", fi);
1643       fwrite(&level,sizeof(int),1,fi);
1644       fwrite(&score,sizeof(int),1,fi);
1645       fwrite(&distros,sizeof(int),1,fi);
1646       fwrite(&scroll_x,sizeof(float),1,fi);
1647       fwrite(&tux,sizeof(Player),1,fi);
1648       timer_fwrite(&tux.invincible_timer,fi);
1649       timer_fwrite(&tux.skidding_timer,fi);
1650       timer_fwrite(&tux.safe_timer,fi);
1651       timer_fwrite(&tux.frame_timer,fi);
1652       timer_fwrite(&time_left,fi);
1653       ui = st_get_ticks();
1654       fwrite(&ui,sizeof(int),1,fi);
1655     }
1656   fclose(fi);
1657
1658 }
1659
1660 void loadgame(int slot)
1661 {
1662   char savefile[1024];
1663   char str[100];
1664   FILE* fi;
1665   unsigned int ui;
1666
1667   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1668
1669   fi = fopen(savefile, "rb");
1670
1671   if (fi == NULL)
1672     {
1673       fprintf(stderr, "Warning: I could not open the slot file ");
1674
1675     }
1676   else
1677     {
1678       fgets(str, 100, fi);
1679       strcpy(level_subset, str);
1680       level_subset[strlen(level_subset)-1] = '\0';
1681       fread(&level,sizeof(int),1,fi);
1682
1683       set_defaults();
1684       level_free(&current_level);
1685       if(level_load(&current_level,level_subset,level) != 0)
1686         exit(1);
1687       arrays_free();
1688       arrays_init();
1689       activate_bad_guys();
1690       level_free_gfx();
1691       level_load_gfx(&current_level);
1692       level_free_song();
1693       level_load_song(&current_level);
1694       levelintro();
1695       update_time = st_get_ticks();
1696
1697       fread(&score,sizeof(int),1,fi);
1698       fread(&distros,sizeof(int),1,fi);
1699       fread(&scroll_x,sizeof(float),1,fi);
1700       fread(&tux, sizeof(Player), 1, fi);
1701       timer_fread(&tux.invincible_timer,fi);
1702       timer_fread(&tux.skidding_timer,fi);
1703       timer_fread(&tux.safe_timer,fi);
1704       timer_fread(&tux.frame_timer,fi);
1705       timer_fread(&time_left,fi);
1706       fread(&ui,sizeof(int),1,fi);
1707       tux.hphysic.start_time += st_get_ticks() - ui;
1708       tux.vphysic.start_time += st_get_ticks() - ui;
1709       fclose(fi);
1710     }
1711
1712 }
1713
1714 void slotinfo(char **pinfo, int slot)
1715 {
1716   FILE* fi;
1717   char slotfile[1024];
1718   char tmp[200];
1719   char str[5];
1720   int slot_level;
1721   sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1722
1723   fi = fopen(slotfile, "rb");
1724
1725   sprintf(tmp,"Slot %d - ",slot);
1726
1727   if (fi == NULL)
1728     {
1729       strcat(tmp,"Free");
1730     }
1731   else
1732     {
1733       fgets(str, 100, fi);
1734       str[strlen(str)-1] = '\0';
1735       strcat(tmp, str);
1736       strcat(tmp, " / Level:");
1737       fread(&slot_level,sizeof(int),1,fi);
1738       sprintf(str,"%d",slot_level);
1739       strcat(tmp,str);
1740       fclose(fi);
1741     }
1742
1743   *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));
1744   strcpy(*pinfo,tmp);
1745 }
1746