- reduced menu fadness a bit (ie. balanced the edges)
[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
300 GameSession::action()
301 {
302   unsigned int i;
303
304   /* (tux.is_dead() || next_level) */
305   if (tux.is_dead() || next_level)
306     {
307       /* Tux either died, or reached the end of a level! */
308
309       halt_music();
310
311
312       if (next_level)
313         {
314           /* End of a level! */
315           level++;
316           next_level = 0;
317           if(st_gl_mode != ST_GL_TEST)
318             {
319               drawresultscreen();
320             }
321           else
322             {
323               level_free_gfx();
324               current_level.cleanup();
325               level_free_song();
326               unloadshared();
327               arrays_free();
328               return(0);
329             }
330           tux.level_begin();
331         }
332       else
333         {
334           tux.is_dying();
335
336           /* No more lives!? */
337
338           if (tux.lives < 0)
339             {
340               if(st_gl_mode != ST_GL_TEST)
341                 drawendscreen();
342
343               if(st_gl_mode != ST_GL_TEST)
344                 {
345                   if (score > hs_score)
346                     save_hs(score);
347                 }
348               level_free_gfx();
349               current_level.cleanup();
350               level_free_song();
351               unloadshared();
352               arrays_free();
353               return(0);
354             } /* if (lives < 0) */
355         }
356
357       /* Either way, (re-)load the (next) level... */
358
359       tux.level_begin();
360       set_defaults();
361       current_level.cleanup();
362
363       if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
364         {
365           if(current_level.load(level_subset) != 0)
366             return 0;
367         }
368       else
369         {
370           if(current_level.load(level_subset,level) != 0)
371             return 0;
372         }
373
374       arrays_free();
375       activate_bad_guys(&current_level);
376       activate_particle_systems();
377       level_free_gfx();
378       current_level.load_gfx();
379       level_free_song();
380       current_level.load_song();
381       if(st_gl_mode != ST_GL_TEST)
382         levelintro();
383       start_timers();
384       /* Play music: */
385       play_current_music();
386     }
387
388   tux.action();
389
390   /* Handle bouncy distros: */
391   for (i = 0; i < bouncy_distros.size(); i++)
392     {
393       bouncy_distro_action(&bouncy_distros[i]);
394     }
395
396
397   /* Handle broken bricks: */
398   for (i = 0; i < broken_bricks.size(); i++)
399     {
400       broken_brick_action(&broken_bricks[i]);
401     }
402
403
404   /* Handle distro counting: */
405
406   if (counting_distros)
407     {
408       distro_counter--;
409
410       if (distro_counter <= 0)
411         counting_distros = -1;
412     }
413
414
415   /* Handle bouncy bricks: */
416
417   for (i = 0; i < bouncy_bricks.size(); i++)
418     {
419       bouncy_brick_action(&bouncy_bricks[i]);
420     }
421
422
423   /* Handle floating scores: */
424
425   for (i = 0; i < floating_scores.size(); i++)
426     {
427       floating_score_action(&floating_scores[i]);
428     }
429
430
431   /* Handle bullets: */
432
433   for (i = 0; i < bullets.size(); ++i)
434     {
435       bullet_action(&bullets[i]);
436     }
437
438   /* Handle upgrades: */
439
440   for (i = 0; i < upgrades.size(); i++)
441     {
442       upgrade_action(&upgrades[i]);
443     }
444
445
446   /* Handle bad guys: */
447
448   for (i = 0; i < bad_guys.size(); i++)
449     {
450       bad_guys[i].action();
451     }
452
453   /* update particle systems */
454   std::vector<ParticleSystem*>::iterator p;
455   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
456     {
457       (*p)->simulate(frame_ratio);
458     }
459
460   /* Handle all possible collisions. */
461   collision_handler();
462
463   return -1;
464 }
465
466 /* --- GAME DRAW! --- */
467
468 void 
469 GameSession::draw()
470 {
471   int y,x;
472
473   /* Draw screen: */
474   if(timer_check(&super_bkgd_timer))
475     texture_draw(&img_super_bkgd, 0, 0);
476   else
477     {
478       /* Draw the real background */
479       if(current_level.bkgd_image[0] != '\0')
480         {
481           int s = (int)scroll_x / 30;
482           texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
483           texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
484         }
485       else
486         {
487           clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
488         }
489     }
490
491   /* Draw particle systems (background) */
492   std::vector<ParticleSystem*>::iterator p;
493   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
494     {
495       (*p)->draw(scroll_x, 0, 0);
496     }
497
498   /* Draw background: */
499
500   for (y = 0; y < 15; ++y)
501     {
502       for (x = 0; x < 21; ++x)
503         {
504           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
505                     current_level.bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
506         }
507     }
508
509   /* Draw interactive tiles: */
510   for (y = 0; y < 15; ++y)
511     {
512       for (x = 0; x < 21; ++x)
513         {
514           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
515                     current_level.ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
516         }
517     }
518
519   /* (Bouncy bricks): */
520   for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
521     bouncy_brick_draw(&bouncy_bricks[i]);
522
523   for (unsigned int i = 0; i < bad_guys.size(); ++i)
524     bad_guys[i].draw();
525
526   tux.draw();
527
528   for (unsigned int i = 0; i < bullets.size(); ++i)
529     bullet_draw(&bullets[i]);
530
531   for (unsigned int i = 0; i < floating_scores.size(); ++i)
532     floating_score_draw(&floating_scores[i]);
533
534   for (unsigned int i = 0; i < upgrades.size(); ++i)
535     upgrade_draw(&upgrades[i]);
536
537   for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
538     bouncy_distro_draw(&bouncy_distros[i]);
539
540   for (unsigned int i = 0; i < broken_bricks.size(); ++i)
541     broken_brick_draw(&broken_bricks[i]);
542
543   /* Draw foreground: */
544   for (y = 0; y < 15; ++y)
545     {
546       for (x = 0; x < 21; ++x)
547         {
548           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
549                     current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
550         }
551     }
552
553   /* Draw particle systems (foreground) */
554   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
555     {
556       (*p)->draw(scroll_x, 0, 1);
557     }
558
559   drawstatus();
560
561   if(game_pause)
562     {
563       int x = screen->h / 20;
564       for(int i = 0; i < x; ++i)
565         {
566           fillrect(i % 2 ? (pause_menu_frame * i)%screen->w : -((pause_menu_frame * i)%screen->w) ,(i*20+pause_menu_frame)%screen->h,screen->w,10,20,20,20, rand() % 20 + 1);
567         }
568       fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
569       text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
570     }
571
572   if(show_menu)
573   {
574     menu_process_current();
575     mouse_cursor->draw();
576   }
577
578   /* (Update it all!) */
579   updatescreen();
580 }
581
582 /* --- GAME LOOP! --- */
583
584 GameSession::GameSession(const char * subset, int levelnb, int mode)
585 {
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   current_level.load_gfx();
612   loadshared();
613   activate_bad_guys(&current_level);
614   activate_particle_systems();
615   current_level.load_song();
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
632 int
633 GameSession::run()
634 {
635   int  fps_cnt;
636   bool jump;
637   bool done;
638
639   /* --- MAIN GAME LOOP!!! --- */
640   jump = false;
641   done = false;
642   quit = 0;
643   global_frame_counter = 0;
644   game_pause = 0;
645   timer_init(&fps_timer,true);
646   timer_init(&frame_timer,true);
647   last_update_time = st_get_ticks();
648   fps_cnt = 0;
649
650   /* Clear screen: */
651   clearscreen(0, 0, 0);
652   updatescreen();
653
654   /* Play music: */
655   play_current_music();
656
657   while (SDL_PollEvent(&event))
658   {}
659
660   draw();
661   do
662     {
663       jump = false;
664
665       /* Calculate the movement-factor */
666       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
667       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
668         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
669
670       if(!timer_check(&frame_timer))
671         {
672           timer_start(&frame_timer,25);
673           ++global_frame_counter;
674         }
675
676       /* Handle events: */
677
678       tux.input.old_fire = tux.input.fire;
679
680       game_event();
681
682       if(show_menu)
683         {
684           if(current_menu == game_menu)
685             {
686               switch (game_menu->check())
687                 {
688                 case 2:
689                   st_pause_ticks_stop();
690                   break;
691                 case 3:
692                   update_load_save_game_menu(save_game_menu, false);
693                   break;
694                 case 4:
695                   update_load_save_game_menu(load_game_menu, true);
696                   break;
697                 case 7:
698                   st_pause_ticks_stop();
699                   done = true;
700                   break;
701                 }
702             }
703           else if(current_menu == options_menu)
704             {
705               process_options_menu();
706             }
707           else if(current_menu == save_game_menu )
708             {
709               process_save_game_menu();
710             }
711           else if(current_menu == load_game_menu )
712             {
713               process_load_game_menu();
714             }
715         }
716
717
718       /* Handle actions: */
719
720       if(!game_pause && !show_menu)
721         {
722           /*float z = frame_ratio;
723             frame_ratio = 1;
724             while(z >= 1)
725             {*/
726           if (action() == 0)
727             {
728               /* == 0: no more lives */
729               /* == -1: continues */
730               return 0;
731             }
732           /*  --z;
733                      }*/
734         }
735       else
736         {
737           ++pause_menu_frame;
738           SDL_Delay(50);
739         }
740
741       if(debug_mode && debug_fps)
742         SDL_Delay(60);
743
744       /*Draw the current scene to the screen */
745       /*If the machine running the game is too slow
746         skip the drawing of the frame (so the calculations are more precise and
747         the FPS aren't affected).*/
748       /*if( ! fps_fps < 50.0 )
749         game_draw();
750         else
751         jump = true;*/ /*FIXME: Implement this tweak right.*/
752       draw();
753
754       /* Time stops in pause mode */
755       if(game_pause || show_menu )
756         {
757           continue;
758         }
759
760       /* Set the time of the last update and the time of the current update */
761       last_update_time = update_time;
762       update_time = st_get_ticks();
763
764       /* Pause till next frame, if the machine running the game is too fast: */
765       /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
766          the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
767       if(last_update_time >= update_time - 12 && !jump) {
768         SDL_Delay(10);
769         update_time = st_get_ticks();
770       }
771       /*if((update_time - last_update_time) < 10)
772         SDL_Delay((11 - (update_time - last_update_time))/2);*/
773
774
775
776       /* Handle time: */
777
778       if (timer_check(&time_left))
779         {
780           /* are we low on time ? */
781           if ((timer_get_left(&time_left) < TIME_WARNING)
782               && (get_current_music() != HURRYUP_MUSIC))     /* play the fast music */
783             {
784               set_current_music(HURRYUP_MUSIC);
785               play_current_music();
786             }
787
788         }
789       else
790         tux.kill(KILL);
791
792
793       /* Calculate frames per second */
794       if(show_fps)
795         {
796           ++fps_cnt;
797           fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
798
799           if(!timer_check(&fps_timer))
800             {
801               timer_start(&fps_timer,1000);
802               fps_cnt = 0;
803             }
804         }
805
806     }
807   while (!done && !quit);
808
809   halt_music();
810
811   level_free_gfx();
812   current_level.cleanup();
813   level_free_song();
814   unloadshared();
815   arrays_free();
816
817   game_started = false;
818
819   return(quit);
820 }
821
822 /* Load graphics/sounds shared between all levels: */
823 void loadshared()
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