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