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