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