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