5d1c64bc976378f45179a50fe35618dbf994d367
[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 st_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(st_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       level_load_gfx(&current_level);
378       level_free_song();
379       level_load_song(&current_level);
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 int gameloop(const char * subset, int levelnb, int mode)
583 {
584   int fps_cnt, jump, done;
585   timer_type fps_timer, frame_timer;
586   timer_init(&fps_timer, true);
587   timer_init(&frame_timer, true);
588
589   game_started = true;
590
591   st_gl_mode = mode;
592   level = levelnb;
593
594   /* Init the game: */
595   arrays_free();
596   set_defaults();
597
598   strcpy(level_subset,subset);
599
600   if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
601     {
602       if (current_level.load(level_subset))
603         exit(1);
604     }
605   else
606     {
607       if(current_level.load(level_subset, level) != 0)
608         exit(1);
609     }
610
611   level_load_gfx(&current_level);
612   loadshared();
613   activate_bad_guys(&current_level);
614   activate_particle_systems();
615   level_load_song(&current_level);
616
617   tux.init();
618
619   if(st_gl_mode != ST_GL_TEST)
620     load_hs();
621
622   if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
623     levelintro();
624
625   timer_init(&time_left,true);
626   start_timers();
627
628   if(st_gl_mode == ST_GL_LOAD_GAME)
629     loadgame(levelnb);
630
631   /* --- MAIN GAME LOOP!!! --- */
632
633   jump = false;
634   done = 0;
635   quit = 0;
636   global_frame_counter = 0;
637   game_pause = 0;
638   timer_init(&fps_timer,true);
639   timer_init(&frame_timer,true);
640   last_update_time = st_get_ticks();
641   fps_cnt = 0;
642
643   /* Clear screen: */
644
645   clearscreen(0, 0, 0);
646   updatescreen();
647
648   /* Play music: */
649   play_current_music();
650
651
652   while (SDL_PollEvent(&event))
653   {}
654
655   game_draw();
656   do
657     {
658       jump = false;
659
660       /* Calculate the movement-factor */
661       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
662       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
663         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
664
665       if(!timer_check(&frame_timer))
666         {
667           timer_start(&frame_timer,25);
668           ++global_frame_counter;
669         }
670
671       /* Handle events: */
672
673       tux.input.old_fire = tux.input.fire;
674
675       game_event();
676
677       if(show_menu)
678         {
679           if(current_menu == game_menu)
680             {
681               switch (game_menu->check())
682                 {
683                 case 2:
684                   st_pause_ticks_stop();
685                   break;
686                 case 3:
687                   update_load_save_game_menu(save_game_menu, false);
688                   break;
689                 case 4:
690                   update_load_save_game_menu(load_game_menu, true);
691                   break;
692                 case 7:
693                   st_pause_ticks_stop();
694                   done = 1;
695                   break;
696                 }
697             }
698           else if(current_menu == options_menu)
699             {
700               process_options_menu();
701             }
702           else if(current_menu == save_game_menu )
703             {
704               process_save_game_menu();
705             }
706           else if(current_menu == load_game_menu )
707             {
708               process_load_game_menu();
709             }
710         }
711
712
713       /* Handle actions: */
714
715       if(!game_pause && !show_menu)
716         {
717           /*float z = frame_ratio;
718             frame_ratio = 1;
719             while(z >= 1)
720             {*/
721           if (game_action() == 0)
722             {
723               /* == 0: no more lives */
724               /* == -1: continues */
725               return 0;
726             }
727           /*  --z;
728                      }*/
729         }
730       else
731         {
732           ++pause_menu_frame;
733           SDL_Delay(50);
734         }
735
736       if(debug_mode && debug_fps)
737         SDL_Delay(60);
738
739       /*Draw the current scene to the screen */
740       /*If the machine running the game is too slow
741         skip the drawing of the frame (so the calculations are more precise and
742         the FPS aren't affected).*/
743       /*if( ! fps_fps < 50.0 )
744         game_draw();
745         else
746         jump = true;*/ /*FIXME: Implement this tweak right.*/
747       game_draw();
748
749       /* Time stops in pause mode */
750       if(game_pause || show_menu )
751         {
752           continue;
753         }
754
755       /* Set the time of the last update and the time of the current update */
756       last_update_time = update_time;
757       update_time = st_get_ticks();
758
759       /* Pause till next frame, if the machine running the game is too fast: */
760       /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
761          the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
762       if(last_update_time >= update_time - 12 && !jump) {
763         SDL_Delay(10);
764         update_time = st_get_ticks();
765       }
766       /*if((update_time - last_update_time) < 10)
767         SDL_Delay((11 - (update_time - last_update_time))/2);*/
768
769
770
771       /* Handle time: */
772
773       if (timer_check(&time_left))
774         {
775           /* are we low on time ? */
776           if ((timer_get_left(&time_left) < TIME_WARNING)
777               && (get_current_music() != HURRYUP_MUSIC))     /* play the fast music */
778             {
779               set_current_music(HURRYUP_MUSIC);
780               play_current_music();
781             }
782
783         }
784       else
785         tux.kill(KILL);
786
787
788       /* Calculate frames per second */
789       if(show_fps)
790         {
791           ++fps_cnt;
792           fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
793
794           if(!timer_check(&fps_timer))
795             {
796               timer_start(&fps_timer,1000);
797               fps_cnt = 0;
798             }
799         }
800
801     }
802   while (!done && !quit);
803
804   halt_music();
805
806   level_free_gfx();
807   current_level.cleanup();
808   level_free_song();
809   unloadshared();
810   arrays_free();
811
812   game_started = false;
813
814   return(quit);
815 }
816
817
818 /* Load graphics/sounds shared between all levels: */
819
820 void loadshared(void)
821 {
822   int i;
823
824   /* Tuxes: */
825   texture_load(&smalltux_stand_left, datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
826   texture_load(&smalltux_stand_right, datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
827
828   texture_load(&smalltux_jump_left, datadir + "/images/shared/smalltux-jump-left.png", USE_ALPHA);
829   texture_load(&smalltux_jump_right, datadir + "/images/shared/smalltux-jump-right.png", USE_ALPHA);
830
831   tux_right.resize(8);
832   texture_load(&tux_right[0], datadir + "/images/shared/smalltux-right-1.png", USE_ALPHA);
833   texture_load(&tux_right[1], datadir + "/images/shared/smalltux-right-2.png", USE_ALPHA);
834   texture_load(&tux_right[2], datadir + "/images/shared/smalltux-right-3.png", USE_ALPHA);
835   texture_load(&tux_right[3], datadir + "/images/shared/smalltux-right-4.png", USE_ALPHA);
836   texture_load(&tux_right[4], datadir + "/images/shared/smalltux-right-5.png", USE_ALPHA);
837   texture_load(&tux_right[5], datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
838   texture_load(&tux_right[6], datadir + "/images/shared/smalltux-right-7.png", USE_ALPHA);
839   texture_load(&tux_right[7], datadir + "/images/shared/smalltux-right-8.png", USE_ALPHA);
840
841   tux_left.resize(8);
842   texture_load(&tux_left[0], datadir + "/images/shared/smalltux-left-1.png", USE_ALPHA);
843   texture_load(&tux_left[1], datadir + "/images/shared/smalltux-left-2.png", USE_ALPHA);
844   texture_load(&tux_left[2], datadir + "/images/shared/smalltux-left-3.png", USE_ALPHA);
845   texture_load(&tux_left[3], datadir + "/images/shared/smalltux-left-4.png", USE_ALPHA);
846   texture_load(&tux_left[4], datadir + "/images/shared/smalltux-left-5.png", USE_ALPHA);
847   texture_load(&tux_left[5], datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
848   texture_load(&tux_left[6], datadir + "/images/shared/smalltux-left-7.png", USE_ALPHA);
849   texture_load(&tux_left[7], datadir + "/images/shared/smalltux-left-8.png", USE_ALPHA);
850
851   texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
852   texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
853   texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
854
855   texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
856   texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
857   texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
858
859
860   texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
861                USE_ALPHA);
862
863   texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
864                USE_ALPHA);
865
866   texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
867                USE_ALPHA);
868
869   texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
870                USE_ALPHA);
871
872   texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
873                USE_ALPHA);
874
875   texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
876                USE_ALPHA);
877
878   texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
879                USE_ALPHA);
880
881   texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
882
883   texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
884                USE_ALPHA);
885
886   texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
887                USE_ALPHA);
888
889   texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
890                USE_ALPHA);
891
892   texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
893
894   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
895                USE_ALPHA);
896
897   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
898                USE_ALPHA);
899
900   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
901                USE_ALPHA);
902
903   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
904                USE_ALPHA);
905
906   texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
907                USE_ALPHA);
908
909   texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
910                USE_ALPHA);
911
912   texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
913                USE_ALPHA);
914
915   texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
916
917   texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
918                USE_ALPHA);
919
920   texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
921                USE_ALPHA);
922
923   texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
924                USE_ALPHA);
925
926   texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
927
928   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
929                USE_ALPHA);
930
931   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
932                USE_ALPHA);
933
934   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
935                USE_ALPHA);
936
937   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
938                USE_ALPHA);
939
940
941   texture_load(&ducktux_right, datadir +
942                "/images/shared/ducktux-right.png",
943                USE_ALPHA);
944
945   texture_load(&ducktux_left, datadir +
946                "/images/shared/ducktux-left.png",
947                USE_ALPHA);
948
949   texture_load(&skidtux_right, datadir +
950                "/images/shared/skidtux-right.png",
951                USE_ALPHA);
952
953   texture_load(&skidtux_left, datadir +
954                "/images/shared/skidtux-left.png",
955                USE_ALPHA);
956
957   texture_load(&duckfiretux_right, datadir +
958                "/images/shared/duckfiretux-right.png",
959                USE_ALPHA);
960
961   texture_load(&duckfiretux_left, datadir +
962                "/images/shared/duckfiretux-left.png",
963                USE_ALPHA);
964
965   texture_load(&skidfiretux_right, datadir +
966                "/images/shared/skidfiretux-right.png",
967                USE_ALPHA);
968
969   texture_load(&skidfiretux_left, datadir +
970                "/images/shared/skidfiretux-left.png",
971                USE_ALPHA);
972
973
974   /* Boxes: */
975
976   texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
977                IGNORE_ALPHA);
978   texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
979                IGNORE_ALPHA);
980
981
982   /* Water: */
983
984
985   texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
986
987   texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
988                USE_ALPHA);
989
990   texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
991                USE_ALPHA);
992
993   texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
994                USE_ALPHA);
995
996
997   /* Pole: */
998
999   texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
1000   texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
1001                USE_ALPHA);
1002
1003
1004   /* Flag: */
1005
1006   texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
1007                USE_ALPHA);
1008   texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
1009                USE_ALPHA);
1010
1011
1012   /* Cloud: */
1013
1014   texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
1015                USE_ALPHA);
1016
1017   texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
1018                USE_ALPHA);
1019
1020   texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
1021                USE_ALPHA);
1022
1023   texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
1024                USE_ALPHA);
1025
1026
1027   texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
1028                USE_ALPHA);
1029
1030   texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
1031                USE_ALPHA);
1032
1033   texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
1034                USE_ALPHA);
1035
1036   texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
1037                USE_ALPHA);
1038
1039
1040   /* Bad guys: */
1041   load_badguy_gfx();
1042
1043   /* Upgrades: */
1044
1045   texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
1046   texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
1047
1048
1049   /* Weapons: */
1050
1051   texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
1052
1053   texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
1054                USE_ALPHA);
1055
1056
1057
1058   /* Distros: */
1059
1060   texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
1061                USE_ALPHA);
1062
1063   texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1064                USE_ALPHA);
1065
1066   texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1067                USE_ALPHA);
1068
1069   texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1070                USE_ALPHA);
1071
1072
1073   /* Tux life: */
1074
1075   texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1076                USE_ALPHA);
1077
1078   /* Herring: */
1079
1080   texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1081                USE_ALPHA);
1082
1083
1084   /* Super background: */
1085
1086   texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1087                IGNORE_ALPHA);
1088
1089
1090   /* Sound effects: */
1091
1092   /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1093                     // initialize sounds[i] with the correct pointer's value:
1094                     // NULL or something else. And it will be dangerous to
1095                     // play with not-initialized pointers.
1096                     // This is also true with if (use_music)
1097                     Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1098   */
1099   for (i = 0; i < NUM_SOUNDS; i++)
1100     sounds[i] = load_sound(datadir + soundfilenames[i]);
1101
1102   /* Herring song */
1103   herring_song = load_song(datadir + "/music/SALCON.MOD");
1104 }
1105
1106
1107 /* Free shared data: */
1108
1109 void unloadshared(void)
1110 {
1111   int i;
1112
1113   for (i = 0; i < 3; i++)
1114     {
1115       texture_free(&tux_right[i]);
1116       texture_free(&tux_left[i]);
1117       texture_free(&bigtux_right[i]);
1118       texture_free(&bigtux_left[i]);
1119     }
1120
1121   texture_free(&bigtux_right_jump);
1122   texture_free(&bigtux_left_jump);
1123
1124   for (i = 0; i < 2; i++)
1125     {
1126       texture_free(&cape_right[i]);
1127       texture_free(&cape_left[i]);
1128       texture_free(&bigcape_right[i]);
1129       texture_free(&bigcape_left[i]);
1130     }
1131
1132   texture_free(&ducktux_left);
1133   texture_free(&ducktux_right);
1134
1135   texture_free(&skidtux_left);
1136   texture_free(&skidtux_right);
1137
1138   free_badguy_gfx();
1139
1140   texture_free(&img_box_full);
1141   texture_free(&img_box_empty);
1142
1143   texture_free(&img_water);
1144   for (i = 0; i < 3; i++)
1145     texture_free(&img_waves[i]);
1146
1147   texture_free(&img_pole);
1148   texture_free(&img_poletop);
1149
1150   for (i = 0; i < 2; i++)
1151     texture_free(&img_flag[i]);
1152
1153   texture_free(&img_mints);
1154   texture_free(&img_coffee);
1155
1156   for (i = 0; i < 4; i++)
1157     {
1158       texture_free(&img_distro[i]);
1159       texture_free(&img_cloud[0][i]);
1160       texture_free(&img_cloud[1][i]);
1161     }
1162
1163   texture_free(&img_golden_herring);
1164
1165   for (i = 0; i < NUM_SOUNDS; i++)
1166     free_chunk(sounds[i]);
1167
1168   /* free the herring song */
1169   free_music( herring_song );
1170 }
1171
1172
1173 /* Draw a tile on the screen: */
1174
1175 void drawshape(float x, float y, unsigned int c, Uint8 alpha)
1176 {
1177   if (c != 0)
1178     {
1179       Tile* ptile = TileManager::instance()->get(c);
1180       if(ptile)
1181         {
1182           if(ptile->images.size() > 1)
1183             {
1184               texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y, alpha);
1185             }
1186           else if (ptile->images.size() == 1)
1187             {
1188               texture_draw(&ptile->images[0],x,y, alpha);
1189             }
1190           else
1191             {
1192               //printf("Tile not dravable %u\n", c);
1193             }
1194         }
1195     }
1196 }
1197
1198 /* Break a brick: */
1199 void trybreakbrick(float x, float y, bool small)
1200 {
1201   Tile* tile = gettile(x, y);
1202   if (tile->brick)
1203     {
1204       if (tile->data > 0)
1205         {
1206           /* Get a distro from it: */
1207           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1208                             (int)(y / 32) * 32);
1209
1210           if (!counting_distros)
1211             {
1212               counting_distros = true;
1213               distro_counter = 50;
1214             }
1215
1216           if (distro_counter <= 0)
1217             level_change(&current_level,x, y, TM_IA, tile->next_tile);
1218
1219           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1220           score = score + SCORE_DISTRO;
1221           distros++;
1222         }
1223       else if (!small)
1224         {
1225           /* Get rid of it: */
1226           level_change(&current_level,x, y, TM_IA, tile->next_tile);
1227           
1228           /* Replace it with broken bits: */
1229           add_broken_brick(((int)(x + 1) / 32) * 32,
1230                            (int)(y / 32) * 32);
1231           
1232           /* Get some score: */
1233           play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1234           score = score + SCORE_BRICK;
1235         }
1236     }
1237 }
1238
1239
1240 /* Bounce a brick: */
1241
1242 void bumpbrick(float x, float y)
1243 {
1244   add_bouncy_brick(((int)(x + 1) / 32) * 32,
1245                    (int)(y / 32) * 32);
1246
1247   play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1248 }
1249
1250 /* Empty a box: */
1251 void tryemptybox(float x, float y, int col_side)
1252 {
1253   Tile* tile = gettile(x,y);
1254   if (!tile->fullbox)
1255     return;
1256
1257   // according to the collision side, set the upgrade direction
1258   if(col_side == LEFT)
1259     col_side = RIGHT;
1260   else
1261     col_side = LEFT;
1262
1263   switch(tile->data)
1264     {
1265     case 1: //'A':      /* Box with a distro! */
1266       add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
1267       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1268       score = score + SCORE_DISTRO;
1269       distros++;
1270       break;
1271
1272     case 2: // 'B':      /* Add an upgrade! */
1273       if (tux.size == SMALL)     /* Tux is small, add mints! */
1274         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
1275       else     /* Tux is big, add coffee: */
1276         add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
1277       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
1278       break;
1279
1280     case 3:// '!':     /* Add a golden herring */
1281       add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
1282       break;
1283     default:
1284       break;
1285     }
1286
1287   /* Empty the box: */
1288   level_change(&current_level,x, y, TM_IA, tile->next_tile);
1289 }
1290
1291 /* Try to grab a distro: */
1292 void trygrabdistro(float x, float y, int bounciness)
1293 {
1294   Tile* tile = gettile(x, y);
1295   if (tile && tile->distro)
1296     {
1297       level_change(&current_level,x, y, TM_IA, tile->next_tile);
1298       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
1299
1300       if (bounciness == BOUNCE)
1301         {
1302           add_bouncy_distro(((int)(x + 1) / 32) * 32,
1303                             (int)(y / 32) * 32);
1304         }
1305
1306       score = score + SCORE_DISTRO;
1307       distros++;
1308     }
1309 }
1310
1311 /* Try to bump a bad guy from below: */
1312 void trybumpbadguy(float x, float y)
1313 {
1314   /* Bad guys: */
1315   for (unsigned int i = 0; i < bad_guys.size(); i++)
1316     {
1317       if (bad_guys[i].base.x >= x - 32 && bad_guys[i].base.x <= x + 32 &&
1318           bad_guys[i].base.y >= y - 16 && bad_guys[i].base.y <= y + 16)
1319         {
1320           bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
1321         }
1322     }
1323
1324
1325   /* Upgrades: */
1326   for (unsigned int i = 0; i < upgrades.size(); i++)
1327     {
1328       if (upgrades[i].base.height == 32 &&
1329           upgrades[i].base.x >= x - 32 && upgrades[i].base.x <= x + 32 &&
1330           upgrades[i].base.y >= y - 16 && upgrades[i].base.y <= y + 16)
1331         {
1332           upgrades[i].base.xm = -upgrades[i].base.xm;
1333           upgrades[i].base.ym = -8;
1334           play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
1335         }
1336     }
1337 }
1338
1339 /* (Status): */
1340 void drawstatus(void)
1341 {
1342   char str[60];
1343
1344   sprintf(str, "%d", score);
1345   text_draw(&white_text, "SCORE", 0, 0, 1);
1346   text_draw(&gold_text, str, 96, 0, 1);
1347
1348   if(st_gl_mode != ST_GL_TEST)
1349     {
1350       sprintf(str, "%d", hs_score);
1351       text_draw(&white_text, "HIGH", 0, 20, 1);
1352       text_draw(&gold_text, str, 96, 20, 1);
1353     }
1354   else
1355     {
1356       text_draw(&white_text,"Press ESC To Return",0,20,1);
1357     }
1358
1359   if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1360     {
1361       sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1362       text_draw(&white_text, "TIME", 224, 0, 1);
1363       text_draw(&gold_text, str, 304, 0, 1);
1364     }
1365
1366   sprintf(str, "%d", distros);
1367   text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1368   text_draw(&gold_text, str, 608, 0, 1);
1369
1370   text_draw(&white_text, "LIVES", screen->h, 20, 1);
1371
1372   if(show_fps)
1373     {
1374       sprintf(str, "%2.1f", fps_fps);
1375       text_draw(&white_text, "FPS", screen->h, 40, 1);
1376       text_draw(&gold_text, str, screen->h + 60, 40, 1);
1377     }
1378
1379   for(int i=0; i < tux.lives; ++i)
1380     {
1381       texture_draw(&tux_life,565+(18*i),20);
1382     }
1383 }
1384
1385
1386 void drawendscreen(void)
1387 {
1388   char str[80];
1389
1390   clearscreen(0, 0, 0);
1391
1392   text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1393
1394   sprintf(str, "SCORE: %d", score);
1395   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1396
1397   sprintf(str, "DISTROS: %d", distros);
1398   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1399
1400   flipscreen();
1401   
1402   SDL_Event event;
1403   wait_for_event(event,2000,5000,true);
1404 }
1405
1406 void drawresultscreen(void)
1407 {
1408   char str[80];
1409
1410   clearscreen(0, 0, 0);
1411
1412   text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1413
1414   sprintf(str, "SCORE: %d", score);
1415   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1416
1417   sprintf(str, "DISTROS: %d", distros);
1418   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1419
1420   flipscreen();
1421   
1422   SDL_Event event;
1423   wait_for_event(event,2000,5000,true);
1424 }
1425
1426 void savegame(int slot)
1427 {
1428   char savefile[1024];
1429   FILE* fi;
1430   unsigned int ui;
1431
1432   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1433
1434   fi = fopen(savefile, "wb");
1435
1436   if (fi == NULL)
1437     {
1438       fprintf(stderr, "Warning: I could not open the slot file ");
1439     }
1440   else
1441     {
1442       fputs(level_subset, fi);
1443       fputs("\n", fi);
1444       fwrite(&level,sizeof(int),1,fi);
1445       fwrite(&score,sizeof(int),1,fi);
1446       fwrite(&distros,sizeof(int),1,fi);
1447       fwrite(&scroll_x,sizeof(float),1,fi);
1448       fwrite(&tux,sizeof(Player),1,fi);
1449       timer_fwrite(&tux.invincible_timer,fi);
1450       timer_fwrite(&tux.skidding_timer,fi);
1451       timer_fwrite(&tux.safe_timer,fi);
1452       timer_fwrite(&tux.frame_timer,fi);
1453       timer_fwrite(&time_left,fi);
1454       ui = st_get_ticks();
1455       fwrite(&ui,sizeof(int),1,fi);
1456     }
1457   fclose(fi);
1458
1459 }
1460
1461 void loadgame(int slot)
1462 {
1463   char savefile[1024];
1464   char str[100];
1465   FILE* fi;
1466   unsigned int ui;
1467
1468   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1469
1470   fi = fopen(savefile, "rb");
1471
1472   if (fi == NULL)
1473     {
1474       fprintf(stderr, "Warning: I could not open the slot file ");
1475
1476     }
1477   else
1478     {
1479       fgets(str, 100, fi);
1480       strcpy(level_subset, str);
1481       level_subset[strlen(level_subset)-1] = '\0';
1482       fread(&level,sizeof(int),1,fi);
1483
1484       set_defaults();
1485       current_level.cleanup();
1486       if(current_level.load(level_subset,level) != 0)
1487         exit(1);
1488       arrays_free();
1489       activate_bad_guys(&current_level);
1490       activate_particle_systems();
1491       level_free_gfx();
1492       level_load_gfx(&current_level);
1493       level_free_song();
1494       level_load_song(&current_level);
1495       levelintro();
1496       update_time = st_get_ticks();
1497
1498       fread(&score,sizeof(int),1,fi);
1499       fread(&distros,sizeof(int),1,fi);
1500       fread(&scroll_x,sizeof(float),1,fi);
1501       fread(&tux, sizeof(Player), 1, fi);
1502       timer_fread(&tux.invincible_timer,fi);
1503       timer_fread(&tux.skidding_timer,fi);
1504       timer_fread(&tux.safe_timer,fi);
1505       timer_fread(&tux.frame_timer,fi);
1506       timer_fread(&time_left,fi);
1507       fread(&ui,sizeof(int),1,fi);
1508       fclose(fi);
1509     }
1510
1511 }
1512
1513 std::string slotinfo(int slot)
1514 {
1515   FILE* fi;
1516   char slotfile[1024];
1517   char tmp[200];
1518   char str[5];
1519   int slot_level;
1520   sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1521
1522   fi = fopen(slotfile, "rb");
1523
1524   sprintf(tmp,"Slot %d - ",slot);
1525
1526   if (fi == NULL)
1527     {
1528       strcat(tmp,"Free");
1529     }
1530   else
1531     {
1532       fgets(str, 100, fi);
1533       str[strlen(str)-1] = '\0';
1534       strcat(tmp, str);
1535       strcat(tmp, " / Level:");
1536       fread(&slot_level,sizeof(int),1,fi);
1537       sprintf(str,"%d",slot_level);
1538       strcat(tmp,str);
1539       fclose(fi);
1540     }
1541
1542   return tmp;
1543 }
1544