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