3b8ceb2dd8a9ea431db175c83a84ac4c51460d95
[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 <math.h>
20 #include <time.h>
21 #include <SDL.h>
22
23 #ifndef WIN32
24 #include <sys/types.h>
25 #include <ctype.h>
26 #endif
27
28 #include "defines.h"
29 #include "globals.h"
30 #include "gameloop.h"
31 #include "screen.h"
32 #include "setup.h"
33 #include "high_scores.h"
34 #include "menu.h"
35 #include "badguy.h"
36 #include "world.h"
37 #include "special.h"
38 #include "player.h"
39 #include "level.h"
40 #include "scene.h"
41 #include "collision.h"
42 #include "tile.h"
43 #include "particlesystem.h"
44
45 /* extern variables */
46
47 Level current_level;
48 int game_started = false;
49
50 /* Local variables: */
51
52 static texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2];
53 static texture_type img_cloud[2][4];
54 static SDL_Event event;
55 static SDLKey key;
56 static char level_subset[100];
57 static float fps_fps;
58 static int st_gl_mode;
59 static unsigned int last_update_time;
60 static unsigned int update_time;
61 static int pause_menu_frame;
62 static int debug_fps;
63
64 /* Local function prototypes: */
65
66 void levelintro(void);
67 void loadshared(void);
68 void unloadshared(void);
69 void drawstatus(void);
70 void drawendscreen(void);
71 void drawresultscreen(void);
72
73 void levelintro(void)
74 {
75   char str[60];
76   /* Level Intro: */
77   clearscreen(0, 0, 0);
78
79   sprintf(str, "LEVEL %d", level);
80   text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
81
82   sprintf(str, "%s", current_level.name.c_str());
83   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
84
85   sprintf(str, "TUX x %d", tux.lives);
86   text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
87
88   flipscreen();
89
90   SDL_Event event;
91   wait_for_event(event,1000,3000,true);
92 }
93
94 /* Reset Timers */
95 void start_timers(void)
96 {
97   timer_start(&time_left,current_level.time_left*1000);
98   st_pause_ticks_init();
99   update_time = st_get_ticks();
100 }
101
102 void activate_bad_guys(Level* plevel)
103 {
104   for (std::vector<BadGuyData>::iterator i = plevel->badguy_data.begin();
105        i != plevel->badguy_data.end();
106        ++i)
107     {
108       add_bad_guy(i->x, i->y, i->kind);
109     }
110 }
111
112 void activate_particle_systems(void)
113 {
114   if(current_level.particle_system == "clouds")
115     {
116       particle_systems.push_back(new CloudParticleSystem);
117     }
118   else if(current_level.particle_system == "snow")
119     {
120       particle_systems.push_back(new SnowParticleSystem);
121     }
122   else if(current_level.particle_system != "")
123     {
124       st_abort("unknown particle system specified in level", "");
125     }
126 }
127
128 /* --- GAME EVENT! --- */
129
130 void game_event(void)
131 {
132   while (SDL_PollEvent(&event))
133     {
134           /* Check for menu-events, if the menu is shown */
135           if(show_menu)
136             menu_event(event);
137       switch(event.type)
138         {
139         case SDL_QUIT:        /* Quit event - quit: */
140           quit = 1;
141           break;
142         case SDL_KEYDOWN:     /* A keypress! */
143           key = event.key.keysym.sym;
144
145           if(tux.key_event(key,DOWN))
146             break;
147
148           switch(key)
149             {
150             case SDLK_ESCAPE:    /* Escape: Open/Close the menu: */
151               if(!game_pause)
152                 {
153                   if(st_gl_mode == ST_GL_TEST)
154                     quit = 1;
155                   else if(show_menu)
156                     {
157                       Menu::set_current(game_menu);
158                       show_menu = 0;
159                       st_pause_ticks_stop();
160                     }
161                   else
162                     {
163                       Menu::set_current(game_menu);
164                       show_menu = 1;
165                       st_pause_ticks_start();
166                     }
167                 }
168               break;
169             default:
170               break;
171             }
172           break;
173         case SDL_KEYUP:      /* A keyrelease! */
174           key = event.key.keysym.sym;
175
176           if(tux.key_event(key, UP))
177             break;
178
179           switch(key)
180             {
181             case SDLK_p:
182               if(!show_menu)
183                 {
184                   if(game_pause)
185                     {
186                       game_pause = 0;
187                       st_pause_ticks_stop();
188                     }
189                   else
190                     {
191                       game_pause = 1;
192                       st_pause_ticks_start();
193                     }
194                 }
195               break;
196             case SDLK_TAB:
197               if(debug_mode)
198                 {
199                   tux.size = !tux.size;
200                   if(tux.size == BIG)
201                     {
202                       tux.base.height = 64;
203                     }
204                   else
205                     tux.base.height = 32;
206                 }
207               break;
208             case SDLK_END:
209               if(debug_mode)
210                 distros += 50;
211               break;
212             case SDLK_SPACE:
213               if(debug_mode)
214                 next_level = 1;
215               break;
216             case SDLK_DELETE:
217               if(debug_mode)
218                 tux.got_coffee = 1;
219               break;
220             case SDLK_INSERT:
221               if(debug_mode)
222                 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
223               break;
224             case SDLK_l:
225               if(debug_mode)
226                 --tux.lives;
227               break;
228             case SDLK_s:
229               if(debug_mode)
230                 score += 1000;
231             case SDLK_f:
232               if(debug_fps)
233                 debug_fps = false;
234               else
235                 debug_fps = true;
236               break;
237             default:
238               break;
239             }
240           break;
241
242         case SDL_JOYAXISMOTION:
243           switch(event.jaxis.axis)
244             {
245             case JOY_X:
246               if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
247                 {
248                   tux.input.left  = DOWN;
249                   tux.input.right = UP;
250                 }
251               else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
252                 {
253                   tux.input.left  = UP;
254                   tux.input.right = DOWN;
255                 }
256               else
257                 {
258                   tux.input.left  = DOWN;
259                   tux.input.right = DOWN;
260                 }
261               break;
262             case JOY_Y:
263               if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
264                 tux.input.down = DOWN;
265               else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
266                 tux.input.down = UP;
267               else
268                 tux.input.down = 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           break;
288
289         default:
290           break;
291
292         }  /* switch */
293
294     } /* while */
295 }
296
297 /* --- GAME ACTION! --- */
298
299 int game_action(void)
300 {
301   unsigned int i;
302
303   /* (tux.is_dead() || next_level) */
304   if (tux.is_dead() || next_level)
305     {
306       /* Tux either died, or reached the end of a level! */
307
308       halt_music();
309
310
311       if (next_level)
312         {
313           /* End of a level! */
314           level++;
315           next_level = 0;
316           if(st_gl_mode != ST_GL_TEST)
317             {
318               drawresultscreen();
319             }
320           else
321             {
322               level_free_gfx();
323               current_level.cleanup();
324               level_free_song();
325               unloadshared();
326               arrays_free();
327               return(0);
328             }
329           tux.level_begin();
330         }
331       else
332         {
333           tux.is_dying();
334
335           /* No more lives!? */
336
337           if (tux.lives < 0)
338             {
339               if(st_gl_mode != ST_GL_TEST)
340                 drawendscreen();
341
342               if(st_gl_mode != ST_GL_TEST)
343                 {
344                   if (score > hs_score)
345                     save_hs(score);
346                 }
347               level_free_gfx();
348               current_level.cleanup();
349               level_free_song();
350               unloadshared();
351               arrays_free();
352               return(0);
353             } /* if (lives < 0) */
354         }
355
356       /* Either way, (re-)load the (next) level... */
357
358       tux.level_begin();
359       set_defaults();
360       current_level.cleanup();
361
362       if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
363         {
364           if(current_level.load(level_subset) != 0)
365             return 0;
366         }
367       else
368         {
369           if(current_level.load(level_subset,level) != 0)
370             return 0;
371         }
372
373       arrays_free();
374       activate_bad_guys(&current_level);
375       activate_particle_systems();
376       level_free_gfx();
377       current_level.load_gfx();
378       level_free_song();
379       current_level.load_song();
380       if(st_gl_mode != ST_GL_TEST)
381         levelintro();
382       start_timers();
383       /* Play music: */
384       play_current_music();
385     }
386
387   tux.action();
388
389   /* Handle bouncy distros: */
390   for (i = 0; i < bouncy_distros.size(); i++)
391     {
392       bouncy_distro_action(&bouncy_distros[i]);
393     }
394
395
396   /* Handle broken bricks: */
397   for (i = 0; i < broken_bricks.size(); i++)
398     {
399       broken_brick_action(&broken_bricks[i]);
400     }
401
402
403   /* Handle distro counting: */
404
405   if (counting_distros)
406     {
407       distro_counter--;
408
409       if (distro_counter <= 0)
410         counting_distros = -1;
411     }
412
413
414   /* Handle bouncy bricks: */
415
416   for (i = 0; i < bouncy_bricks.size(); i++)
417     {
418       bouncy_brick_action(&bouncy_bricks[i]);
419     }
420
421
422   /* Handle floating scores: */
423
424   for (i = 0; i < floating_scores.size(); i++)
425     {
426       floating_score_action(&floating_scores[i]);
427     }
428
429
430   /* Handle bullets: */
431
432   for (i = 0; i < bullets.size(); ++i)
433     {
434       bullet_action(&bullets[i]);
435     }
436
437   /* Handle upgrades: */
438
439   for (i = 0; i < upgrades.size(); i++)
440     {
441       upgrade_action(&upgrades[i]);
442     }
443
444
445   /* Handle bad guys: */
446
447   for (i = 0; i < bad_guys.size(); i++)
448     {
449       bad_guys[i].action();
450     }
451
452   /* update particle systems */
453   std::vector<ParticleSystem*>::iterator p;
454   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
455     {
456       (*p)->simulate(frame_ratio);
457     }
458
459   /* Handle all possible collisions. */
460   collision_handler();
461
462   return -1;
463 }
464
465 /* --- GAME DRAW! --- */
466
467 void game_draw(void)
468 {
469   int y,x;
470
471   /* Draw screen: */
472   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           int 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 particle systems (background) */
490   std::vector<ParticleSystem*>::iterator p;
491   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
492     {
493       (*p)->draw(scroll_x, 0, 0);
494     }
495
496   /* Draw background: */
497
498   for (y = 0; y < 15; ++y)
499     {
500       for (x = 0; x < 21; ++x)
501         {
502           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
503                     current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
504         }
505     }
506
507   /* Draw interactive tiles: */
508   for (y = 0; y < 15; ++y)
509     {
510       for (x = 0; x < 21; ++x)
511         {
512           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
513                     current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
514         }
515     }
516
517   /* (Bouncy bricks): */
518   for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
519     bouncy_brick_draw(&bouncy_bricks[i]);
520
521   for (unsigned int i = 0; i < bad_guys.size(); ++i)
522     bad_guys[i].draw();
523
524   tux.draw();
525
526   for (unsigned int i = 0; i < bullets.size(); ++i)
527     bullet_draw(&bullets[i]);
528
529   for (unsigned int i = 0; i < floating_scores.size(); ++i)
530     floating_score_draw(&floating_scores[i]);
531
532   for (unsigned int i = 0; i < upgrades.size(); ++i)
533     upgrade_draw(&upgrades[i]);
534
535   for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
536     bouncy_distro_draw(&bouncy_distros[i]);
537
538   for (unsigned int i = 0; i < broken_bricks.size(); ++i)
539     broken_brick_draw(&broken_bricks[i]);
540
541   /* Draw foreground: */
542   for (y = 0; y < 15; ++y)
543     {
544       for (x = 0; x < 21; ++x)
545         {
546           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
547                     current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
548         }
549     }
550
551   /* Draw particle systems (foreground) */
552   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
553     {
554       (*p)->draw(scroll_x, 0, 1);
555     }
556
557   drawstatus();
558
559   if(game_pause)
560     {
561       int x = screen->h / 20;
562       for(int i = 0; i < x; ++i)
563         {
564           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);
565         }
566       fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
567       text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
568     }
569
570   if(show_menu)
571   {
572     menu_process_current();
573     mouse_cursor->draw();
574   }
575
576   /* (Update it all!) */
577   updatescreen();
578 }
579
580 /* --- GAME LOOP! --- */
581
582 GameSession::GameSession(const char * subset, int levelnb, int mode)
583 {
584   timer_init(&fps_timer, true);
585   timer_init(&frame_timer, true);
586
587   game_started = true;
588
589   st_gl_mode = mode;
590   level = levelnb;
591
592   /* Init the game: */
593   arrays_free();
594   set_defaults();
595
596   strcpy(level_subset,subset);
597
598   if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
599     {
600       if (current_level.load(level_subset))
601         exit(1);
602     }
603   else
604     {
605       if(current_level.load(level_subset, level) != 0)
606         exit(1);
607     }
608
609   current_level.load_gfx();
610   loadshared();
611   activate_bad_guys(&current_level);
612   activate_particle_systems();
613   current_level.load_song();
614
615   tux.init();
616
617   if(st_gl_mode != ST_GL_TEST)
618     load_hs();
619
620   if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
621     levelintro();
622
623   timer_init(&time_left,true);
624   start_timers();
625
626   if(st_gl_mode == ST_GL_LOAD_GAME)
627     loadgame(levelnb);
628 }
629
630 int
631 GameSession::run()
632 {
633   int  fps_cnt;
634   bool jump;
635   bool done;
636
637   /* --- MAIN GAME LOOP!!! --- */
638   jump = false;
639   done = false;
640   quit = 0;
641   global_frame_counter = 0;
642   game_pause = 0;
643   timer_init(&fps_timer,true);
644   timer_init(&frame_timer,true);
645   last_update_time = st_get_ticks();
646   fps_cnt = 0;
647
648   /* Clear screen: */
649   clearscreen(0, 0, 0);
650   updatescreen();
651
652   /* Play music: */
653   play_current_music();
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           ++global_frame_counter;
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 = true;
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_game_menu();
708             }
709           else if(current_menu == load_game_menu )
710             {
711               process_load_game_menu();
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)
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       /* 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         update_time = st_get_ticks();
768       }
769       /*if((update_time - last_update_time) < 10)
770         SDL_Delay((11 - (update_time - last_update_time))/2);*/
771
772
773
774       /* Handle time: */
775
776       if (timer_check(&time_left))
777         {
778           /* are we low on time ? */
779           if ((timer_get_left(&time_left) < TIME_WARNING)
780               && (get_current_music() != HURRYUP_MUSIC))     /* play the fast music */
781             {
782               set_current_music(HURRYUP_MUSIC);
783               play_current_music();
784             }
785
786         }
787       else
788         tux.kill(KILL);
789
790
791       /* Calculate frames per second */
792       if(show_fps)
793         {
794           ++fps_cnt;
795           fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
796
797           if(!timer_check(&fps_timer))
798             {
799               timer_start(&fps_timer,1000);
800               fps_cnt = 0;
801             }
802         }
803
804     }
805   while (!done && !quit);
806
807   halt_music();
808
809   level_free_gfx();
810   current_level.cleanup();
811   level_free_song();
812   unloadshared();
813   arrays_free();
814
815   game_started = false;
816
817   return(quit);
818 }
819
820
821 /* Load graphics/sounds shared between all levels: */
822
823 void loadshared(void)
824 {
825   int i;
826
827   /* Tuxes: */
828   texture_load(&smalltux_stand_left, datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
829   texture_load(&smalltux_stand_right, datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
830
831   texture_load(&smalltux_jump_left, datadir + "/images/shared/smalltux-jump-left.png", USE_ALPHA);
832   texture_load(&smalltux_jump_right, datadir + "/images/shared/smalltux-jump-right.png", USE_ALPHA);
833
834   tux_right.resize(8);
835   texture_load(&tux_right[0], datadir + "/images/shared/smalltux-right-1.png", USE_ALPHA);
836   texture_load(&tux_right[1], datadir + "/images/shared/smalltux-right-2.png", USE_ALPHA);
837   texture_load(&tux_right[2], datadir + "/images/shared/smalltux-right-3.png", USE_ALPHA);
838   texture_load(&tux_right[3], datadir + "/images/shared/smalltux-right-4.png", USE_ALPHA);
839   texture_load(&tux_right[4], datadir + "/images/shared/smalltux-right-5.png", USE_ALPHA);
840   texture_load(&tux_right[5], datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
841   texture_load(&tux_right[6], datadir + "/images/shared/smalltux-right-7.png", USE_ALPHA);
842   texture_load(&tux_right[7], datadir + "/images/shared/smalltux-right-8.png", USE_ALPHA);
843
844   tux_left.resize(8);
845   texture_load(&tux_left[0], datadir + "/images/shared/smalltux-left-1.png", USE_ALPHA);
846   texture_load(&tux_left[1], datadir + "/images/shared/smalltux-left-2.png", USE_ALPHA);
847   texture_load(&tux_left[2], datadir + "/images/shared/smalltux-left-3.png", USE_ALPHA);
848   texture_load(&tux_left[3], datadir + "/images/shared/smalltux-left-4.png", USE_ALPHA);
849   texture_load(&tux_left[4], datadir + "/images/shared/smalltux-left-5.png", USE_ALPHA);
850   texture_load(&tux_left[5], datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
851   texture_load(&tux_left[6], datadir + "/images/shared/smalltux-left-7.png", USE_ALPHA);
852   texture_load(&tux_left[7], datadir + "/images/shared/smalltux-left-8.png", USE_ALPHA);
853
854   texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
855   texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
856   texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
857
858   texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
859   texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
860   texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
861
862
863   texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
864                USE_ALPHA);
865
866   texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
867                USE_ALPHA);
868
869   texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
870                USE_ALPHA);
871
872   texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
873                USE_ALPHA);
874
875   texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
876                USE_ALPHA);
877
878   texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
879                USE_ALPHA);
880
881   texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
882                USE_ALPHA);
883
884   texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
885
886   texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
887                USE_ALPHA);
888
889   texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
890                USE_ALPHA);
891
892   texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
893                USE_ALPHA);
894
895   texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
896
897   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
898                USE_ALPHA);
899
900   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
901                USE_ALPHA);
902
903   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
904                USE_ALPHA);
905
906   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
907                USE_ALPHA);
908
909   texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
910                USE_ALPHA);
911
912   texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
913                USE_ALPHA);
914
915   texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
916                USE_ALPHA);
917
918   texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
919
920   texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
921                USE_ALPHA);
922
923   texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
924                USE_ALPHA);
925
926   texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
927                USE_ALPHA);
928
929   texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
930
931   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
932                USE_ALPHA);
933
934   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
935                USE_ALPHA);
936
937   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
938                USE_ALPHA);
939
940   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
941                USE_ALPHA);
942
943
944   texture_load(&ducktux_right, datadir +
945                "/images/shared/ducktux-right.png",
946                USE_ALPHA);
947
948   texture_load(&ducktux_left, datadir +
949                "/images/shared/ducktux-left.png",
950                USE_ALPHA);
951
952   texture_load(&skidtux_right, datadir +
953                "/images/shared/skidtux-right.png",
954                USE_ALPHA);
955
956   texture_load(&skidtux_left, datadir +
957                "/images/shared/skidtux-left.png",
958                USE_ALPHA);
959
960   texture_load(&duckfiretux_right, datadir +
961                "/images/shared/duckfiretux-right.png",
962                USE_ALPHA);
963
964   texture_load(&duckfiretux_left, datadir +
965                "/images/shared/duckfiretux-left.png",
966                USE_ALPHA);
967
968   texture_load(&skidfiretux_right, datadir +
969                "/images/shared/skidfiretux-right.png",
970                USE_ALPHA);
971
972   texture_load(&skidfiretux_left, datadir +
973                "/images/shared/skidfiretux-left.png",
974                USE_ALPHA);
975
976
977   /* Boxes: */
978
979   texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
980                IGNORE_ALPHA);
981   texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
982                IGNORE_ALPHA);
983
984
985   /* Water: */
986
987
988   texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
989
990   texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
991                USE_ALPHA);
992
993   texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
994                USE_ALPHA);
995
996   texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
997                USE_ALPHA);
998
999
1000   /* Pole: */
1001
1002   texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
1003   texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1004                USE_ALPHA);
1005
1006
1007   /* Flag: */
1008
1009   texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1010                USE_ALPHA);
1011   texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1012                USE_ALPHA);
1013
1014
1015   /* Cloud: */
1016
1017   texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1018                USE_ALPHA);
1019
1020   texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1021                USE_ALPHA);
1022
1023   texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1024                USE_ALPHA);
1025
1026   texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1027                USE_ALPHA);
1028
1029
1030   texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1031                USE_ALPHA);
1032
1033   texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1034                USE_ALPHA);
1035
1036   texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1037                USE_ALPHA);
1038
1039   texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1040                USE_ALPHA);
1041
1042
1043   /* Bad guys: */
1044   load_badguy_gfx();
1045
1046   /* Upgrades: */
1047
1048   texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1049   texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1050
1051
1052   /* Weapons: */
1053
1054   texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1055
1056   texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1057                USE_ALPHA);
1058
1059
1060
1061   /* Distros: */
1062
1063   texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1064                USE_ALPHA);
1065
1066   texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1067                USE_ALPHA);
1068
1069   texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1070                USE_ALPHA);
1071
1072   texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1073                USE_ALPHA);
1074
1075
1076   /* Tux life: */
1077
1078   texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1079                USE_ALPHA);
1080
1081   /* Herring: */
1082
1083   texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1084                USE_ALPHA);
1085
1086
1087   /* Super background: */
1088
1089   texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1090                IGNORE_ALPHA);
1091
1092
1093   /* Sound effects: */
1094
1095   /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1096                     // initialize sounds[i] with the correct pointer's value:
1097                     // NULL or something else. And it will be dangerous to
1098                     // play with not-initialized pointers.
1099                     // This is also true with if (use_music)
1100                     Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1101   */
1102   for (i = 0; i < NUM_SOUNDS; i++)
1103     sounds[i] = load_sound(datadir + soundfilenames[i]);
1104
1105   /* Herring song */
1106   herring_song = load_song(datadir + "/music/SALCON.MOD");
1107 }
1108
1109
1110 /* Free shared data: */
1111
1112 void unloadshared(void)
1113 {
1114   int i;
1115
1116   for (i = 0; i < 3; i++)
1117     {
1118       texture_free(&tux_right[i]);
1119       texture_free(&tux_left[i]);
1120       texture_free(&bigtux_right[i]);
1121       texture_free(&bigtux_left[i]);
1122     }
1123
1124   texture_free(&bigtux_right_jump);
1125   texture_free(&bigtux_left_jump);
1126
1127   for (i = 0; i < 2; i++)
1128     {
1129       texture_free(&cape_right[i]);
1130       texture_free(&cape_left[i]);
1131       texture_free(&bigcape_right[i]);
1132       texture_free(&bigcape_left[i]);
1133     }
1134
1135   texture_free(&ducktux_left);
1136   texture_free(&ducktux_right);
1137
1138   texture_free(&skidtux_left);
1139   texture_free(&skidtux_right);
1140
1141   free_badguy_gfx();
1142
1143   texture_free(&img_box_full);
1144   texture_free(&img_box_empty);
1145
1146   texture_free(&img_water);
1147   for (i = 0; i < 3; i++)
1148     texture_free(&img_waves[i]);
1149
1150   texture_free(&img_pole);
1151   texture_free(&img_poletop);
1152
1153   for (i = 0; i < 2; i++)
1154     texture_free(&img_flag[i]);
1155
1156   texture_free(&img_mints);
1157   texture_free(&img_coffee);
1158
1159   for (i = 0; i < 4; i++)
1160     {
1161       texture_free(&img_distro[i]);
1162       texture_free(&img_cloud[0][i]);
1163       texture_free(&img_cloud[1][i]);
1164     }
1165
1166   texture_free(&img_golden_herring);
1167
1168   for (i = 0; i < NUM_SOUNDS; i++)
1169     free_chunk(sounds[i]);
1170
1171   /* free the herring song */
1172   free_music( herring_song );
1173 }
1174
1175
1176 /* Draw a tile on the screen: */
1177
1178 void drawshape(float x, float y, unsigned int c, Uint8 alpha)
1179 {
1180   if (c != 0)
1181     {
1182       Tile* ptile = TileManager::instance()->get(c);
1183       if(ptile)
1184         {
1185           if(ptile->images.size() > 1)
1186             {
1187               texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y, alpha);
1188             }
1189           else if (ptile->images.size() == 1)
1190             {
1191               texture_draw(&ptile->images[0],x,y, alpha);
1192             }
1193           else
1194             {
1195               //printf("Tile not dravable %u\n", c);
1196             }
1197         }
1198     }
1199 }
1200
1201 /* Break a brick: */
1202 void trybreakbrick(float x, float y, bool small)
1203 {
1204   Tile* tile = gettile(x, y);
1205   if (tile->brick)
1206     {
1207       if (tile->data > 0)
1208         {
1209           /* Get a distro from it: */
1210           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1211                             (int)(y / 32) * 32);
1212
1213           if (!counting_distros)
1214             {
1215               counting_distros = true;
1216               distro_counter = 50;
1217             }
1218
1219           if (distro_counter <= 0)
1220             current_level.change(x, y, TM_IA, tile->next_tile);
1221
1222           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1223           score = score + SCORE_DISTRO;
1224           distros++;
1225         }
1226       else if (!small)
1227         {
1228           /* Get rid of it: */
1229           current_level.change(x, y, TM_IA, tile->next_tile);
1230           
1231           /* Replace it with broken bits: */
1232           add_broken_brick(((int)(x + 1) / 32) * 32,
1233                            (int)(y / 32) * 32);
1234           
1235           /* Get some score: */
1236           play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1237           score = score + SCORE_BRICK;
1238         }
1239     }
1240 }
1241
1242
1243 /* Bounce a brick: */
1244
1245 void bumpbrick(float x, float y)
1246 {
1247   add_bouncy_brick(((int)(x + 1) / 32) * 32,
1248                    (int)(y / 32) * 32);
1249
1250   play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1251 }
1252
1253 /* Empty a box: */
1254 void tryemptybox(float x, float y, int col_side)
1255 {
1256   Tile* tile = gettile(x,y);
1257   if (!tile->fullbox)
1258     return;
1259
1260   // according to the collision side, set the upgrade direction
1261   if(col_side == LEFT)
1262     col_side = RIGHT;
1263   else
1264     col_side = LEFT;
1265
1266   switch(tile->data)
1267     {
1268     case 1: //'A':      /* Box with a distro! */
1269       add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1270       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1271       score = score + SCORE_DISTRO;
1272       distros++;
1273       break;
1274
1275     case 2: // 'B':      /* Add an upgrade! */
1276       if (tux.size == SMALL)     /* Tux is small, add mints! */
1277         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1278       else     /* Tux is big, add coffee: */
1279         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1280       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1281       break;
1282
1283     case 3:// '!':     /* Add a golden herring */
1284       add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1285       break;
1286     default:
1287       break;
1288     }
1289
1290   /* Empty the box: */
1291   current_level.change(x, y, TM_IA, tile->next_tile);
1292 }
1293
1294 /* Try to grab a distro: */
1295 void trygrabdistro(float x, float y, int bounciness)
1296 {
1297   Tile* tile = gettile(x, y);
1298   if (tile && tile->distro)
1299     {
1300       current_level.change(x, y, TM_IA, tile->next_tile);
1301       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1302
1303       if (bounciness == BOUNCE)
1304         {
1305           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1306                             (int)(y / 32) * 32);
1307         }
1308
1309       score = score + SCORE_DISTRO;
1310       distros++;
1311     }
1312 }
1313
1314 /* Try to bump a bad guy from below: */
1315 void trybumpbadguy(float x, float y)
1316 {
1317   /* Bad guys: */
1318   for (unsigned int i = 0; i < bad_guys.size(); i++)
1319     {
1320       if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1321           bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1322         {
1323           bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1324         }
1325     }
1326
1327
1328   /* Upgrades: */
1329   for (unsigned int i = 0; i < upgrades.size(); i++)
1330     {
1331       if (upgrades[i].base.height == 32 &&
1332           upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1333           upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1334         {
1335           upgrades[i].base.xm = -upgrades[i].base.xm;
1336           upgrades[i].base.ym = -8;
1337           play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1338         }
1339     }
1340 }
1341
1342 /* (Status): */
1343 void drawstatus(void)
1344 {
1345   char str[60];
1346
1347   sprintf(str, "%d", score);
1348   text_draw(&white_text, "SCORE", 0, 0, 1);
1349   text_draw(&gold_text, str, 96, 0, 1);
1350
1351   if(st_gl_mode != ST_GL_TEST)
1352     {
1353       sprintf(str, "%d", hs_score);
1354       text_draw(&white_text, "HIGH", 0, 20, 1);
1355       text_draw(&gold_text, str, 96, 20, 1);
1356     }
1357   else
1358     {
1359       text_draw(&white_text,"Press ESC To Return",0,20,1);
1360     }
1361
1362   if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1363     {
1364       sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1365       text_draw(&white_text, "TIME", 224, 0, 1);
1366       text_draw(&gold_text, str, 304, 0, 1);
1367     }
1368
1369   sprintf(str, "%d", distros);
1370   text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1371   text_draw(&gold_text, str, 608, 0, 1);
1372
1373   text_draw(&white_text, "LIVES", screen->h, 20, 1);
1374
1375   if(show_fps)
1376     {
1377       sprintf(str, "%2.1f", fps_fps);
1378       text_draw(&white_text, "FPS", screen->h, 40, 1);
1379       text_draw(&gold_text, str, screen->h + 60, 40, 1);
1380     }
1381
1382   for(int i=0; i < tux.lives; ++i)
1383     {
1384       texture_draw(&tux_life,565+(18*i),20);
1385     }
1386 }
1387
1388
1389 void drawendscreen(void)
1390 {
1391   char str[80];
1392
1393   clearscreen(0, 0, 0);
1394
1395   text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1396
1397   sprintf(str, "SCORE: %d", score);
1398   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1399
1400   sprintf(str, "DISTROS: %d", distros);
1401   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1402
1403   flipscreen();
1404   
1405   SDL_Event event;
1406   wait_for_event(event,2000,5000,true);
1407 }
1408
1409 void drawresultscreen(void)
1410 {
1411   char str[80];
1412
1413   clearscreen(0, 0, 0);
1414
1415   text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1416
1417   sprintf(str, "SCORE: %d", score);
1418   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1419
1420   sprintf(str, "DISTROS: %d", distros);
1421   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1422
1423   flipscreen();
1424   
1425   SDL_Event event;
1426   wait_for_event(event,2000,5000,true);
1427 }
1428
1429 void savegame(int slot)
1430 {
1431   char savefile[1024];
1432   FILE* fi;
1433   unsigned int ui;
1434
1435   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1436
1437   fi = fopen(savefile, "wb");
1438
1439   if (fi == NULL)
1440     {
1441       fprintf(stderr, "Warning: I could not open the slot file ");
1442     }
1443   else
1444     {
1445       fputs(level_subset, fi);
1446       fputs("\n", fi);
1447       fwrite(&level,sizeof(int),1,fi);
1448       fwrite(&score,sizeof(int),1,fi);
1449       fwrite(&distros,sizeof(int),1,fi);
1450       fwrite(&scroll_x,sizeof(float),1,fi);
1451       fwrite(&tux,sizeof(Player),1,fi);
1452       timer_fwrite(&tux.invincible_timer,fi);
1453       timer_fwrite(&tux.skidding_timer,fi);
1454       timer_fwrite(&tux.safe_timer,fi);
1455       timer_fwrite(&tux.frame_timer,fi);
1456       timer_fwrite(&time_left,fi);
1457       ui = st_get_ticks();
1458       fwrite(&ui,sizeof(int),1,fi);
1459     }
1460   fclose(fi);
1461
1462 }
1463
1464 void loadgame(int slot)
1465 {
1466   char savefile[1024];
1467   char str[100];
1468   FILE* fi;
1469   unsigned int ui;
1470
1471   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1472
1473   fi = fopen(savefile, "rb");
1474
1475   if (fi == NULL)
1476     {
1477       fprintf(stderr, "Warning: I could not open the slot file ");
1478
1479     }
1480   else
1481     {
1482       fgets(str, 100, fi);
1483       strcpy(level_subset, str);
1484       level_subset[strlen(level_subset)-1] = '\0';
1485       fread(&level,sizeof(int),1,fi);
1486
1487       set_defaults();
1488       current_level.cleanup();
1489       if(current_level.load(level_subset,level) != 0)
1490         exit(1);
1491       arrays_free();
1492       activate_bad_guys(&current_level);
1493       activate_particle_systems();
1494       level_free_gfx();
1495       current_level.load_gfx();
1496       level_free_song();
1497       current_level.load_song();
1498       levelintro();
1499       update_time = st_get_ticks();
1500
1501       fread(&score,sizeof(int),1,fi);
1502       fread(&distros,sizeof(int),1,fi);
1503       fread(&scroll_x,sizeof(float),1,fi);
1504       fread(&tux, sizeof(Player), 1, fi);
1505       timer_fread(&tux.invincible_timer,fi);
1506       timer_fread(&tux.skidding_timer,fi);
1507       timer_fread(&tux.safe_timer,fi);
1508       timer_fread(&tux.frame_timer,fi);
1509       timer_fread(&time_left,fi);
1510       fread(&ui,sizeof(int),1,fi);
1511       fclose(fi);
1512     }
1513
1514 }
1515
1516 std::string slotinfo(int slot)
1517 {
1518   FILE* fi;
1519   char slotfile[1024];
1520   char tmp[200];
1521   char str[5];
1522   int slot_level;
1523   sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1524
1525   fi = fopen(slotfile, "rb");
1526
1527   sprintf(tmp,"Slot %d - ",slot);
1528
1529   if (fi == NULL)
1530     {
1531       strcat(tmp,"Free");
1532     }
1533   else
1534     {
1535       fgets(str, 100, fi);
1536       str[strlen(str)-1] = '\0';
1537       strcat(tmp, str);
1538       strcat(tmp, " / Level:");
1539       fread(&slot_level,sizeof(int),1,fi);
1540       sprintf(str,"%d",slot_level);
1541       strcat(tmp,str);
1542       fclose(fi);
1543     }
1544
1545   return tmp;
1546 }
1547