9dd970cd7563dce71020c7f2458dd1d2188920c0
[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     for (int x = 0; x < 21; ++x)
486       drawshape(32*x - fmodf(scroll_x, 32), y * 32,
487                 current_level.tiles[y][x + (int)(scroll_x / 32)]);
488
489   for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
490     bouncy_brick_draw(&bouncy_bricks[i]);
491
492   for (unsigned int i = 0; i < bad_guys.size(); ++i)
493     bad_guys[i].draw();
494
495   tux.draw();
496
497   for (unsigned int i = 0; i < bullets.size(); ++i)
498     bullet_draw(&bullets[i]);
499
500   for (unsigned int i = 0; i < floating_scores.size(); ++i)
501     floating_score_draw(&floating_scores[i]);
502
503   for (unsigned int i = 0; i < upgrades.size(); ++i)
504     upgrade_draw(&upgrades[i]);
505
506   for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
507       bouncy_distro_draw(&bouncy_distros[i]);
508
509   for (unsigned int i = 0; i < broken_bricks.size(); ++i)
510     broken_brick_draw(&broken_bricks[i]);
511
512   drawstatus();
513
514   if(game_pause)
515     {
516       int x = screen->h / 20;
517       for(int i = 0; i < x; ++i)
518         {
519           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);
520         }
521       fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
522       text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
523     }
524
525   if(show_menu)
526     menu_process_current();
527
528   /* (Update it all!) */
529
530   updatescreen();
531
532
533 }
534
535 /* --- GAME LOOP! --- */
536
537 int gameloop(const char * subset, int levelnb, int mode)
538 {
539   int fps_cnt, jump, done;
540   timer_type fps_timer, frame_timer;
541   timer_init(&fps_timer, true);
542   timer_init(&frame_timer, true);
543
544   game_started = true;
545
546   st_gl_mode = mode;
547   level = levelnb;
548
549   /* Init the game: */
550   arrays_init();
551   set_defaults();
552
553   strcpy(level_subset,subset);
554
555   if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
556     {
557       if (level_load(&current_level, level_subset))
558         exit(1);
559     }
560   else
561     {
562       if(level_load(&current_level, level_subset, level) != 0)
563         exit(1);
564     }
565
566   level_load_gfx(&current_level);
567   activate_bad_guys();
568   level_load_song(&current_level);
569
570   tux.init();
571
572   if(st_gl_mode != ST_GL_TEST)
573     load_hs();
574
575   loadshared();
576
577   if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
578     levelintro();
579
580   timer_init(&time_left,true);
581   start_timers();
582
583   if(st_gl_mode == ST_GL_LOAD_GAME)
584     loadgame(levelnb);
585
586
587   /* --- MAIN GAME LOOP!!! --- */
588
589   jump = false;
590   done = 0;
591   quit = 0;
592   global_frame_counter = 0;
593   game_pause = 0;
594   timer_init(&fps_timer,true);
595   timer_init(&frame_timer,true);
596   fps_cnt = 0;
597
598   /* Clear screen: */
599
600   clearscreen(0, 0, 0);
601   updatescreen();
602
603   /* Play music: */
604   play_current_music();
605
606
607   while (SDL_PollEvent(&event))
608     {}
609
610   game_draw();
611   do
612     {
613       jump = false;
614
615       /* Calculate the movement-factor */
616       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
617       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
618         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
619       
620       if(!timer_check(&frame_timer))
621         {
622           timer_start(&frame_timer,25);
623           ++global_frame_counter;
624         }
625
626       /* Handle events: */
627
628       tux.input_.old_fire = tux.input_.fire;
629
630       game_event();
631
632       if(show_menu)
633         {
634           if(current_menu == game_menu)
635             {
636               switch (game_menu->check())
637                 {
638                 case 2:
639                   st_pause_ticks_stop();
640                   break;
641                 case 3:
642                   update_load_save_game_menu(save_game_menu, false);
643                   break;
644                 case 4:
645                   update_load_save_game_menu(load_game_menu, true);
646                   break;
647                 case 7:
648                   st_pause_ticks_stop();
649                   done = 1;
650                   break;
651                 }
652             }
653           else if(current_menu == options_menu)
654             {
655               process_options_menu();
656             }
657           else if(current_menu == save_game_menu )
658             {
659               process_save_load_game_menu(true);
660             }
661           else if(current_menu == load_game_menu )
662             {
663               process_save_load_game_menu(false);
664             }
665         }
666
667
668       /* Handle actions: */
669
670       if(!game_pause && !show_menu)
671         {
672           /*float z = frame_ratio;
673             frame_ratio = 1;
674             while(z >= 1)
675             {*/
676           if (game_action() == 0)
677             {
678               /* == 0: no more lives */
679               /* == -1: continues */
680               return 0;
681             }
682           /*  --z;
683               }*/
684         }
685       else
686         {
687           ++pause_menu_frame;
688           SDL_Delay(50);
689         }
690
691       if(debug_mode && debug_fps)
692         SDL_Delay(60);
693
694       /*Draw the current scene to the screen */
695       /*If the machine running the game is too slow
696         skip the drawing of the frame (so the calculations are more precise and
697         the FPS aren't affected).*/
698       /*if( ! fps_fps < 50.0 )
699         game_draw();
700         else
701         jump = true;*/ /*FIXME: Implement this tweak right.*/
702       game_draw();
703
704       /* Time stops in pause mode */
705       if(game_pause || show_menu )
706         {
707           continue;
708         }
709
710       /* Set the time of the last update and the time of the current update */
711       last_update_time = update_time;
712       update_time = st_get_ticks();
713
714
715       /* Pause till next frame, if the machine running the game is too fast: */
716       /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
717          the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
718       if(last_update_time >= update_time - 12 && !jump)
719         SDL_Delay(10);
720       /*if((update_time - last_update_time) < 10)
721         SDL_Delay((11 - (update_time - last_update_time))/2);*/
722
723
724
725       /* Handle time: */
726
727       if (timer_check(&time_left))
728         {
729           /* are we low on time ? */
730           if ((timer_get_left(&time_left) < TIME_WARNING)
731               && (get_current_music() != HURRYUP_MUSIC))     /* play the fast music */
732             {
733               set_current_music(HURRYUP_MUSIC);
734               play_current_music();
735             }
736
737         }
738       else
739         tux.kill(KILL);
740
741
742       /* Calculate frames per second */
743       if(show_fps)
744         {
745           ++fps_cnt;
746           fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
747
748           if(!timer_check(&fps_timer))
749             {
750               timer_start(&fps_timer,1000);
751               fps_cnt = 0;
752             }
753         }
754
755     }
756   while (!done && !quit);
757
758   halt_music();
759
760   level_free_gfx();
761   level_free(&current_level);
762   level_free_song();
763   unloadshared();
764   arrays_free();
765
766   game_started = false;
767
768   return(quit);
769 }
770
771
772 /* Load graphics/sounds shared between all levels: */
773
774 void loadshared(void)
775 {
776   int i;
777
778   /* Tuxes: */
779   texture_load(&tux_right[0], datadir + "/images/shared/tux-right-0.png", USE_ALPHA);
780   texture_load(&tux_right[1], datadir + "/images/shared/tux-right-1.png", USE_ALPHA);
781   texture_load(&tux_right[2], datadir + "/images/shared/tux-right-2.png", USE_ALPHA);
782
783   texture_load(&tux_left[0], datadir + "/images/shared/tux-left-0.png", USE_ALPHA);
784   texture_load(&tux_left[1], datadir + "/images/shared/tux-left-1.png", USE_ALPHA);
785   texture_load(&tux_left[2], datadir + "/images/shared/tux-left-2.png", USE_ALPHA);
786
787   texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
788   texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
789   texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
790
791   texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
792   texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
793   texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
794
795
796   texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
797                USE_ALPHA);
798
799   texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
800                USE_ALPHA);
801
802   texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
803                USE_ALPHA);
804
805   texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
806                USE_ALPHA);
807
808   texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
809                USE_ALPHA);
810
811   texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
812                USE_ALPHA);
813
814   texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
815                USE_ALPHA);
816
817   texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
818
819   texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
820                USE_ALPHA);
821
822   texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
823                USE_ALPHA);
824
825   texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
826                USE_ALPHA);
827
828   texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
829
830   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
831                USE_ALPHA);
832
833   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
834                USE_ALPHA);
835
836   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
837                USE_ALPHA);
838
839   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
840                USE_ALPHA);
841
842   texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
843                USE_ALPHA);
844
845   texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
846                USE_ALPHA);
847
848   texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
849                USE_ALPHA);
850
851   texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
852
853   texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
854                USE_ALPHA);
855
856   texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
857                USE_ALPHA);
858
859   texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
860                USE_ALPHA);
861
862   texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
863
864   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
865                USE_ALPHA);
866
867   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
868                USE_ALPHA);
869
870   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
871                USE_ALPHA);
872
873   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
874                USE_ALPHA);
875
876
877   texture_load(&ducktux_right, datadir +
878                "/images/shared/ducktux-right.png",
879                USE_ALPHA);
880
881   texture_load(&ducktux_left, datadir +
882                "/images/shared/ducktux-left.png",
883                USE_ALPHA);
884
885   texture_load(&skidtux_right, datadir +
886                "/images/shared/skidtux-right.png",
887                USE_ALPHA);
888
889   texture_load(&skidtux_left, datadir +
890                "/images/shared/skidtux-left.png",
891                USE_ALPHA);
892
893   texture_load(&duckfiretux_right, datadir +
894                "/images/shared/duckfiretux-right.png",
895                USE_ALPHA);
896
897   texture_load(&duckfiretux_left, datadir +
898                "/images/shared/duckfiretux-left.png",
899                USE_ALPHA);
900
901   texture_load(&skidfiretux_right, datadir +
902                "/images/shared/skidfiretux-right.png",
903                USE_ALPHA);
904
905   texture_load(&skidfiretux_left, datadir +
906                "/images/shared/skidfiretux-left.png",
907                USE_ALPHA);
908
909
910   /* Boxes: */
911
912   texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
913                IGNORE_ALPHA);
914   texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
915                IGNORE_ALPHA);
916
917
918   /* Water: */
919
920
921   texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
922
923   texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
924                USE_ALPHA);
925
926   texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
927                USE_ALPHA);
928
929   texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
930                USE_ALPHA);
931
932
933   /* Pole: */
934
935   texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
936   texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
937                USE_ALPHA);
938
939
940   /* Flag: */
941
942   texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
943                USE_ALPHA);
944   texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
945                USE_ALPHA);
946
947
948   /* Cloud: */
949
950   texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
951                USE_ALPHA);
952
953   texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
954                USE_ALPHA);
955
956   texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
957                USE_ALPHA);
958
959   texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
960                USE_ALPHA);
961
962
963   texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
964                USE_ALPHA);
965
966   texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
967                USE_ALPHA);
968
969   texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
970                USE_ALPHA);
971
972   texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
973                USE_ALPHA);
974
975
976   /* Bad guys: */
977
978   /* (BSOD) */
979
980   texture_load(&img_bsod_left[0], datadir +
981                "/images/shared/bsod-left-0.png",
982                USE_ALPHA);
983
984   texture_load(&img_bsod_left[1], datadir +
985                "/images/shared/bsod-left-1.png",
986                USE_ALPHA);
987
988   texture_load(&img_bsod_left[2], datadir +
989                "/images/shared/bsod-left-2.png",
990                USE_ALPHA);
991
992   texture_load(&img_bsod_left[3], datadir +
993                "/images/shared/bsod-left-3.png",
994                USE_ALPHA);
995
996   texture_load(&img_bsod_right[0], datadir +
997                "/images/shared/bsod-right-0.png",
998                USE_ALPHA);
999
1000   texture_load(&img_bsod_right[1], datadir +
1001                "/images/shared/bsod-right-1.png",
1002                USE_ALPHA);
1003
1004   texture_load(&img_bsod_right[2], datadir +
1005                "/images/shared/bsod-right-2.png",
1006                USE_ALPHA);
1007
1008   texture_load(&img_bsod_right[3], datadir +
1009                "/images/shared/bsod-right-3.png",
1010                USE_ALPHA);
1011
1012   texture_load(&img_bsod_squished_left, datadir +
1013                "/images/shared/bsod-squished-left.png",
1014                USE_ALPHA);
1015
1016   texture_load(&img_bsod_squished_right, datadir +
1017                "/images/shared/bsod-squished-right.png",
1018                USE_ALPHA);
1019
1020   texture_load(&img_bsod_falling_left, datadir +
1021                "/images/shared/bsod-falling-left.png",
1022                USE_ALPHA);
1023
1024   texture_load(&img_bsod_falling_right, datadir +
1025                "/images/shared/bsod-falling-right.png",
1026                USE_ALPHA);
1027
1028
1029   /* (Laptop) */
1030
1031   texture_load(&img_laptop_left[0], datadir +
1032                "/images/shared/laptop-left-0.png",
1033                USE_ALPHA);
1034
1035   texture_load(&img_laptop_left[1], datadir +
1036                "/images/shared/laptop-left-1.png",
1037                USE_ALPHA);
1038
1039   texture_load(&img_laptop_left[2], datadir +
1040                "/images/shared/laptop-left-2.png",
1041                USE_ALPHA);
1042
1043   texture_load(&img_laptop_right[0], datadir +
1044                "/images/shared/laptop-right-0.png",
1045                USE_ALPHA);
1046
1047   texture_load(&img_laptop_right[1], datadir +
1048                "/images/shared/laptop-right-1.png",
1049                USE_ALPHA);
1050
1051   texture_load(&img_laptop_right[2], datadir +
1052                "/images/shared/laptop-right-2.png",
1053                USE_ALPHA);
1054
1055   texture_load(&img_laptop_flat_left, datadir +
1056                "/images/shared/laptop-flat-left.png",
1057                USE_ALPHA);
1058
1059   texture_load(&img_laptop_flat_right, datadir +
1060                "/images/shared/laptop-flat-right.png",
1061                USE_ALPHA);
1062
1063   texture_load(&img_laptop_falling_left, datadir +
1064                "/images/shared/laptop-falling-left.png",
1065                USE_ALPHA);
1066
1067   texture_load(&img_laptop_falling_right, datadir +
1068                "/images/shared/laptop-falling-right.png",
1069                USE_ALPHA);
1070
1071
1072   /* (Money) */
1073
1074   texture_load(&img_money_left[0], datadir +
1075                "/images/shared/bag-left-0.png",
1076                USE_ALPHA);
1077
1078   texture_load(&img_money_left[1], datadir +
1079                "/images/shared/bag-left-1.png",
1080                USE_ALPHA);
1081
1082   texture_load(&img_money_right[0], datadir +
1083                "/images/shared/bag-right-0.png",
1084                USE_ALPHA);
1085
1086   texture_load(&img_money_right[1], datadir +
1087                "/images/shared/bag-right-1.png",
1088                USE_ALPHA);
1089
1090
1091
1092   /* Upgrades: */
1093
1094   texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1095   texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1096
1097
1098   /* Weapons: */
1099
1100   texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1101
1102   texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1103                USE_ALPHA);
1104
1105
1106
1107   /* Distros: */
1108
1109   texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1110                USE_ALPHA);
1111
1112   texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1113                USE_ALPHA);
1114
1115   texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1116                USE_ALPHA);
1117
1118   texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1119                USE_ALPHA);
1120
1121
1122   /* Tux life: */
1123
1124   texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1125                USE_ALPHA);
1126
1127   /* Herring: */
1128
1129   texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1130                USE_ALPHA);
1131
1132
1133   /* Super background: */
1134
1135   texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1136                IGNORE_ALPHA);
1137
1138
1139   /* Sound effects: */
1140
1141   /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1142                     // initialize sounds[i] with the correct pointer's value:
1143                     // NULL or something else. And it will be dangerous to
1144                     // play with not-initialized pointers.
1145                     // This is also true with if (use_music)
1146                     Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1147   */
1148   for (i = 0; i < NUM_SOUNDS; i++)
1149     sounds[i] = load_sound(datadir + soundfilenames[i]);
1150
1151   /* Herring song */
1152   herring_song = load_song(datadir + "/music/SALCON.MOD");
1153 }
1154
1155
1156 /* Free shared data: */
1157
1158 void unloadshared(void)
1159 {
1160   int i;
1161
1162   for (i = 0; i < 3; i++)
1163     {
1164       texture_free(&tux_right[i]);
1165       texture_free(&tux_left[i]);
1166       texture_free(&bigtux_right[i]);
1167       texture_free(&bigtux_left[i]);
1168     }
1169
1170   texture_free(&bigtux_right_jump);
1171   texture_free(&bigtux_left_jump);
1172
1173   for (i = 0; i < 2; i++)
1174     {
1175       texture_free(&cape_right[i]);
1176       texture_free(&cape_left[i]);
1177       texture_free(&bigcape_right[i]);
1178       texture_free(&bigcape_left[i]);
1179     }
1180
1181   texture_free(&ducktux_left);
1182   texture_free(&ducktux_right);
1183
1184   texture_free(&skidtux_left);
1185   texture_free(&skidtux_right);
1186
1187   for (i = 0; i < 4; i++)
1188     {
1189       texture_free(&img_bsod_left[i]);
1190       texture_free(&img_bsod_right[i]);
1191     }
1192
1193   texture_free(&img_bsod_squished_left);
1194   texture_free(&img_bsod_squished_right);
1195
1196   texture_free(&img_bsod_falling_left);
1197   texture_free(&img_bsod_falling_right);
1198
1199   for (i = 0; i < 3; i++)
1200     {
1201       texture_free(&img_laptop_left[i]);
1202       texture_free(&img_laptop_right[i]);
1203     }
1204
1205   texture_free(&img_laptop_flat_left);
1206   texture_free(&img_laptop_flat_right);
1207
1208   texture_free(&img_laptop_falling_left);
1209   texture_free(&img_laptop_falling_right);
1210
1211   for (i = 0; i < 2; i++)
1212     {
1213       texture_free(&img_money_left[i]);
1214       texture_free(&img_money_right[i]);
1215     }
1216
1217   texture_free(&img_box_full);
1218   texture_free(&img_box_empty);
1219
1220   texture_free(&img_water);
1221   for (i = 0; i < 3; i++)
1222     texture_free(&img_waves[i]);
1223
1224   texture_free(&img_pole);
1225   texture_free(&img_poletop);
1226
1227   for (i = 0; i < 2; i++)
1228     texture_free(&img_flag[i]);
1229
1230   texture_free(&img_mints);
1231   texture_free(&img_coffee);
1232
1233   for (i = 0; i < 4; i++)
1234     {
1235       texture_free(&img_distro[i]);
1236       texture_free(&img_cloud[0][i]);
1237       texture_free(&img_cloud[1][i]);
1238     }
1239
1240   texture_free(&img_golden_herring);
1241
1242   for (i = 0; i < NUM_SOUNDS; i++)
1243     free_chunk(sounds[i]);
1244
1245   /* free the herring song */
1246   free_music( herring_song );
1247 }
1248
1249
1250 /* Draw a tile on the screen: */
1251
1252 void drawshape(float x, float y, unsigned char c)
1253 {
1254   int z;
1255
1256   if (c == 'X' || c == 'x')
1257     texture_draw(&img_brick[0], x, y);
1258   else if (c == 'Y' || c == 'y')
1259     texture_draw(&img_brick[1], x, y);
1260   else if (c == 'A' || c =='B' || c == '!')
1261     texture_draw(&img_box_full, x, y);
1262   else if (c == 'a')
1263     texture_draw(&img_box_empty, x, y);
1264   else if (c >= 'C' && c <= 'F')
1265     texture_draw(&img_cloud[0][c - 'C'], x, y);
1266   else if (c >= 'c' && c <= 'f')
1267     texture_draw(&img_cloud[1][c - 'c'], x, y);
1268   else if (c >= 'G' && c <= 'J')
1269     texture_draw(&img_bkgd_tile[0][c - 'G'], x, y);
1270   else if (c >= 'g' && c <= 'j')
1271     texture_draw(&img_bkgd_tile[1][c - 'g'], x, y);
1272   else if (c == '#')
1273     texture_draw(&img_solid[0], x, y);
1274   else if (c == '[')
1275     texture_draw(&img_solid[1], x, y);
1276   else if (c == '=')
1277     texture_draw(&img_solid[2], x, y);
1278   else if (c == ']')
1279     texture_draw(&img_solid[3], x, y);
1280   else if (c == '$')
1281     {
1282       z = (global_frame_counter / 2) % 6;
1283
1284       if (z < 4)
1285         texture_draw(&img_distro[z], x, y);
1286       else if (z == 4)
1287         texture_draw(&img_distro[2], x, y);
1288       else if (z == 5)
1289         texture_draw(&img_distro[1], x, y);
1290     }
1291   else if (c == '^')
1292     {
1293       z = (global_frame_counter / 3) % 3;
1294
1295       texture_draw(&img_waves[z], x, y);
1296     }
1297   else if (c == '*')
1298     texture_draw(&img_poletop, x, y);
1299   else if (c == '|')
1300     {
1301       texture_draw(&img_pole, x, y);
1302
1303     }
1304   else if (c == '\\')
1305     {
1306       z = (global_frame_counter / 3) % 2;
1307
1308       texture_draw(&img_flag[z], x + 16, y);
1309     }
1310   else if (c == '&')
1311     texture_draw(&img_water, x, y);
1312 }
1313
1314
1315 /* What shape is at some position? */
1316
1317 unsigned char shape(float x, float y)
1318 {
1319
1320   int xx, yy;
1321   unsigned char c;
1322
1323   yy = ((int)y / 32);
1324   xx = ((int)x / 32);
1325
1326   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
1327     {
1328       c = current_level.tiles[yy][xx];
1329     }
1330   else
1331     c = '.';
1332
1333   return(c);
1334 }
1335
1336 /* Is is ground? */
1337
1338
1339 bool issolid(float x, float y)
1340 {
1341   return (isbrick(x, y) ||
1342           isice(x, y) ||
1343           (shape(x, y) == '[') ||
1344           (shape(x, y) == '=') ||
1345           (shape(x, y) == ']') ||
1346           (shape(x, y) == 'A') ||
1347           (shape(x, y) == 'B') ||
1348           (shape(x, y) == '!') ||
1349           (shape(x, y) == 'a'));
1350 }
1351
1352 /* Is it a brick? */
1353
1354 bool isbrick(float x, float y)
1355 {
1356   return (shape(x, y) == 'X' ||
1357           shape(x, y) == 'x' ||
1358           shape(x, y) == 'Y' ||
1359           shape(x, y) == 'y');
1360 }
1361
1362
1363 /* Is it ice? */
1364
1365 bool isice(float x, float y)
1366 {
1367   return (shape(x, y) == '#');
1368 }
1369
1370 /* Is it a full box? */
1371
1372 bool isfullbox(float x, float y)
1373 {
1374   return (shape(x, y) == 'A' ||
1375           shape(x, y) == 'B' ||
1376           shape(x, y) == '!');
1377 }
1378
1379 /* Break a brick: */
1380
1381 void trybreakbrick(float x, float y)
1382 {
1383   if (isbrick(x, y))
1384     {
1385       if (shape(x, y) == 'x' || shape(x, y) == 'y')
1386         {
1387           /* Get a distro from it: */
1388
1389           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1390                             (int)(y / 32) * 32);
1391
1392           if (!counting_distros)
1393             {
1394               counting_distros = true;
1395               distro_counter = 50;
1396             }
1397
1398           if (distro_counter <= 0)
1399             level_change(&current_level,x, y, 'a');
1400
1401           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1402           score = score + SCORE_DISTRO;
1403           distros++;
1404         }
1405       else
1406         {
1407           /* Get rid of it: */
1408
1409           level_change(&current_level,x, y,'.');
1410         }
1411
1412
1413       /* Replace it with broken bits: */
1414
1415       add_broken_brick(((int)(x + 1) / 32) * 32,
1416                        (int)(y / 32) * 32);
1417
1418
1419       /* Get some score: */
1420
1421       play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1422       score = score + SCORE_BRICK;
1423     }
1424 }
1425
1426
1427 /* Bounce a brick: */
1428
1429 void bumpbrick(float x, float y)
1430 {
1431   add_bouncy_brick(((int)(x + 1) / 32) * 32,
1432                    (int)(y / 32) * 32);
1433
1434   play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1435
1436 }
1437
1438
1439 /* Empty a box: */
1440
1441 void tryemptybox(float x, float y, int col_side)
1442 {
1443   if (!isfullbox(x, y))
1444     return;
1445
1446   // according to the collision side, set the upgrade direction
1447
1448   if(col_side == LEFT)
1449     col_side = RIGHT;
1450   else
1451     col_side = LEFT;
1452
1453   switch(shape(x,y))
1454     {
1455     case 'A':      /* Box with a distro! */
1456       add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1457       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1458       score = score + SCORE_DISTRO;
1459       distros++;
1460       break;
1461     case 'B':      /* Add an upgrade! */
1462       if (tux.size == SMALL)     /* Tux is small, add mints! */
1463         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1464       else     /* Tux is big, add coffee: */
1465         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1466       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1467       break;
1468     case '!':     /* Add a golden herring */
1469       add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1470       break;
1471     default:
1472       break;
1473     }
1474
1475   /* Empty the box: */
1476   level_change(&current_level,x, y, 'a');
1477 }
1478
1479
1480 /* Try to grab a distro: */
1481
1482 void trygrabdistro(float x, float y, int bounciness)
1483 {
1484   if (shape(x, y) == '$')
1485     {
1486       level_change(&current_level,x, y, '.');
1487       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1488
1489       if (bounciness == BOUNCE)
1490         {
1491           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1492                             (int)(y / 32) * 32);
1493         }
1494
1495       score = score + SCORE_DISTRO;
1496       distros++;
1497     }
1498 }
1499
1500 /* Try to bump a bad guy from below: */
1501
1502 void trybumpbadguy(float x, float y)
1503 {
1504   unsigned int i;
1505
1506   /* Bad guys: */
1507   for (i = 0; i < bad_guys.size(); i++)
1508     {
1509       if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1510           bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1511         {
1512           if (bad_guys[i].kind == BAD_BSOD ||
1513               bad_guys[i].kind == BAD_LAPTOP)
1514             {
1515               bad_guys[i].dying = DYING_FALLING;
1516               bad_guys[i].base.ym = -8;
1517               play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
1518             }
1519         }
1520     }
1521
1522
1523   /* Upgrades: */
1524   for (i = 0; i < upgrades.size(); i++)
1525     {
1526       if (upgrades[i].base.height == 32 &&
1527           upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1528           upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1529         {
1530           upgrades[i].base.xm = -upgrades[i].base.xm;
1531           upgrades[i].base.ym = -8;
1532           play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1533         }
1534     }
1535 }
1536
1537 /* (Status): */
1538 void drawstatus(void)
1539 {
1540   char str[60];
1541
1542   sprintf(str, "%d", score);
1543   text_draw(&white_text, "SCORE", 0, 0, 1);
1544   text_draw(&gold_text, str, 96, 0, 1);
1545
1546   if(st_gl_mode != ST_GL_TEST)
1547     {
1548       sprintf(str, "%d", hs_score);
1549       text_draw(&white_text, "HIGH", 0, 20, 1);
1550       text_draw(&gold_text, str, 96, 20, 1);
1551     }
1552   else
1553     {
1554       text_draw(&white_text,"Press ESC To Return",0,20,1);
1555     }
1556
1557   if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1558     {
1559       sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1560       text_draw(&white_text, "TIME", 224, 0, 1);
1561       text_draw(&gold_text, str, 304, 0, 1);
1562     }
1563
1564   sprintf(str, "%d", distros);
1565   text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1566   text_draw(&gold_text, str, 608, 0, 1);
1567
1568   text_draw(&white_text, "LIVES", screen->h, 20, 1);
1569
1570   if(show_fps)
1571     {
1572       sprintf(str, "%2.1f", fps_fps);
1573       text_draw(&white_text, "FPS", screen->h, 40, 1);
1574       text_draw(&gold_text, str, screen->h + 60, 40, 1);
1575     }
1576
1577   for(int i=0; i < tux.lives; ++i)
1578     {
1579       texture_draw(&tux_life,565+(18*i),20);
1580     }
1581 }
1582
1583
1584 void drawendscreen(void)
1585 {
1586   char str[80];
1587
1588   clearscreen(0, 0, 0);
1589
1590   text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1591
1592   sprintf(str, "SCORE: %d", score);
1593   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1594
1595   sprintf(str, "DISTROS: %d", distros);
1596   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1597
1598   flipscreen();
1599   SDL_Delay(2000);
1600 }
1601
1602 void drawresultscreen(void)
1603 {
1604   char str[80];
1605
1606   clearscreen(0, 0, 0);
1607
1608   text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1609
1610   sprintf(str, "SCORE: %d", score);
1611   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1612
1613   sprintf(str, "DISTROS: %d", distros);
1614   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1615
1616   flipscreen();
1617   SDL_Delay(2000);
1618 }
1619
1620 void savegame(int slot)
1621 {
1622   char savefile[1024];
1623   FILE* fi;
1624   unsigned int ui;
1625
1626   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1627
1628   fi = fopen(savefile, "wb");
1629
1630   if (fi == NULL)
1631     {
1632       fprintf(stderr, "Warning: I could not open the slot file ");
1633
1634     }
1635   else
1636     {
1637       fputs(level_subset, fi);
1638       fputs("\n", fi);
1639       fwrite(&level,sizeof(int),1,fi);
1640       fwrite(&score,sizeof(int),1,fi);
1641       fwrite(&distros,sizeof(int),1,fi);
1642       fwrite(&scroll_x,sizeof(float),1,fi);
1643       fwrite(&tux,sizeof(Player),1,fi);
1644       timer_fwrite(&tux.invincible_timer,fi);
1645       timer_fwrite(&tux.skidding_timer,fi);
1646       timer_fwrite(&tux.safe_timer,fi);
1647       timer_fwrite(&tux.frame_timer,fi);
1648       timer_fwrite(&time_left,fi);
1649       ui = st_get_ticks();
1650       fwrite(&ui,sizeof(int),1,fi);
1651     }
1652   fclose(fi);
1653
1654 }
1655
1656 void loadgame(int slot)
1657 {
1658   char savefile[1024];
1659   char str[100];
1660   FILE* fi;
1661   unsigned int ui;
1662
1663   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1664
1665   fi = fopen(savefile, "rb");
1666
1667   if (fi == NULL)
1668     {
1669       fprintf(stderr, "Warning: I could not open the slot file ");
1670
1671     }
1672   else
1673     {
1674       fgets(str, 100, fi);
1675       strcpy(level_subset, str);
1676       level_subset[strlen(level_subset)-1] = '\0';
1677       fread(&level,sizeof(int),1,fi);
1678
1679       set_defaults();
1680       level_free(&current_level);
1681       if(level_load(&current_level,level_subset,level) != 0)
1682         exit(1);
1683       arrays_free();
1684       arrays_init();
1685       activate_bad_guys();
1686       level_free_gfx();
1687       level_load_gfx(&current_level);
1688       level_free_song();
1689       level_load_song(&current_level);
1690       levelintro();
1691       update_time = st_get_ticks();
1692
1693       fread(&score,sizeof(int),1,fi);
1694       fread(&distros,sizeof(int),1,fi);
1695       fread(&scroll_x,sizeof(float),1,fi);
1696       fread(&tux, sizeof(Player), 1, fi);
1697       timer_fread(&tux.invincible_timer,fi);
1698       timer_fread(&tux.skidding_timer,fi);
1699       timer_fread(&tux.safe_timer,fi);
1700       timer_fread(&tux.frame_timer,fi);
1701       timer_fread(&time_left,fi);
1702       fread(&ui,sizeof(int),1,fi);
1703       tux.hphysic.start_time += st_get_ticks() - ui;
1704       tux.vphysic.start_time += st_get_ticks() - ui;
1705       fclose(fi);
1706     }
1707
1708 }
1709
1710 void slotinfo(char **pinfo, int slot)
1711 {
1712   FILE* fi;
1713   char slotfile[1024];
1714   char tmp[200];
1715   char str[5];
1716   int slot_level;
1717   sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1718
1719   fi = fopen(slotfile, "rb");
1720
1721   sprintf(tmp,"Slot %d - ",slot);
1722
1723   if (fi == NULL)
1724     {
1725       strcat(tmp,"Free");
1726     }
1727   else
1728     {
1729       fgets(str, 100, fi);
1730       str[strlen(str)-1] = '\0';
1731       strcat(tmp, str);
1732       strcat(tmp, " / Level:");
1733       fread(&slot_level,sizeof(int),1,fi);
1734       sprintf(str,"%d",slot_level);
1735       strcat(tmp,str);
1736       fclose(fi);
1737     }
1738
1739   *pinfo = (char*) malloc(sizeof(char) * (strlen(tmp)+1));
1740   strcpy(*pinfo,tmp);
1741 }
1742