- moved stuff from scene into a World class, just an intermediate step, more cleanup...
[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 <assert.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <math.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <math.h>
21 #include <time.h>
22 #include <SDL.h>
23
24 #ifndef WIN32
25 #include <sys/types.h>
26 #include <ctype.h>
27 #endif
28
29 #include "defines.h"
30 #include "globals.h"
31 #include "gameloop.h"
32 #include "screen.h"
33 #include "setup.h"
34 #include "high_scores.h"
35 #include "menu.h"
36 #include "badguy.h"
37 #include "world.h"
38 #include "special.h"
39 #include "player.h"
40 #include "level.h"
41 #include "scene.h"
42 #include "collision.h"
43 #include "tile.h"
44 #include "particlesystem.h"
45
46 /* extern variables */
47
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 GameSession* GameSession::current_ = 0;
65
66 /* Local function prototypes: */
67 void levelintro(void);
68 void loadshared(void);
69 void unloadshared(void);
70 void drawstatus(void);
71 void drawendscreen(void);
72 void drawresultscreen(void);
73
74 GameSession::GameSession()
75 {
76   current_ = this;
77   assert(0);
78 }
79
80 GameSession::GameSession(const std::string& filename)
81 {
82   current_ = this;
83
84   timer_init(&fps_timer, true);
85   timer_init(&frame_timer, true);
86
87   current_level.load(filename);
88 }
89
90 GameSession::GameSession(const std::string& subset, int levelnb, int mode)
91 {
92   current_ = this;
93
94   timer_init(&fps_timer, true);
95   timer_init(&frame_timer, true);
96
97   game_started = true;
98
99   st_gl_mode = mode;
100   level = levelnb;
101
102   /* Init the game: */
103   world.arrays_free();
104   set_defaults();
105
106   strcpy(level_subset, subset.c_str());
107
108   if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
109     {
110       if (current_level.load(level_subset))
111         exit(1);
112     }
113   else
114     {
115       if(current_level.load(level_subset, level) != 0)
116         exit(1);
117     }
118
119   current_level.load_gfx();
120   loadshared();
121   activate_bad_guys(&current_level);
122   activate_particle_systems();
123   current_level.load_song();
124
125   tux.init();
126
127   if(st_gl_mode != ST_GL_TEST)
128     load_hs();
129
130   if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
131     levelintro();
132
133   timer_init(&time_left,true);
134   start_timers();
135
136   if(st_gl_mode == ST_GL_LOAD_GAME)
137     loadgame(levelnb);
138 }
139
140 void
141 GameSession::levelintro(void)
142 {
143   char str[60];
144   /* Level Intro: */
145   clearscreen(0, 0, 0);
146
147   sprintf(str, "LEVEL %d", level);
148   text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
149
150   sprintf(str, "%s", current_level.name.c_str());
151   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
152
153   sprintf(str, "TUX x %d", tux.lives);
154   text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
155
156   flipscreen();
157
158   SDL_Event event;
159   wait_for_event(event,1000,3000,true);
160 }
161
162 /* Reset Timers */
163 void
164 GameSession::start_timers()
165 {
166   timer_start(&time_left,current_level.time_left*1000);
167   st_pause_ticks_init();
168   update_time = st_get_ticks();
169 }
170
171 void activate_bad_guys(Level* plevel)
172 {
173   for (std::vector<BadGuyData>::iterator i = plevel->badguy_data.begin();
174        i != plevel->badguy_data.end();
175        ++i)
176     {
177       world.add_bad_guy(i->x, i->y, i->kind);
178     }
179 }
180
181 void
182 GameSession::activate_particle_systems()
183 {
184   if(current_level.particle_system == "clouds")
185     {
186       world.particle_systems.push_back(new CloudParticleSystem);
187     }
188   else if(current_level.particle_system == "snow")
189     {
190       world.particle_systems.push_back(new SnowParticleSystem);
191     }
192   else if(current_level.particle_system != "")
193     {
194       st_abort("unknown particle system specified in level", "");
195     }
196 }
197
198 void
199 GameSession::process_events()
200 {
201   while (SDL_PollEvent(&event))
202     {
203           /* Check for menu-events, if the menu is shown */
204           if(show_menu)
205             menu_event(event);
206       switch(event.type)
207         {
208         case SDL_QUIT:        /* Quit event - quit: */
209           quit = 1;
210           break;
211         case SDL_KEYDOWN:     /* A keypress! */
212           key = event.key.keysym.sym;
213
214           if(tux.key_event(key,DOWN))
215             break;
216
217           switch(key)
218             {
219             case SDLK_ESCAPE:    /* Escape: Open/Close the menu: */
220               if(!game_pause)
221                 {
222                   if(st_gl_mode == ST_GL_TEST)
223                     quit = 1;
224                   else if(show_menu)
225                     {
226                       Menu::set_current(game_menu);
227                       show_menu = 0;
228                       st_pause_ticks_stop();
229                     }
230                   else
231                     {
232                       Menu::set_current(game_menu);
233                       show_menu = 1;
234                       st_pause_ticks_start();
235                     }
236                 }
237               break;
238             default:
239               break;
240             }
241           break;
242         case SDL_KEYUP:      /* A keyrelease! */
243           key = event.key.keysym.sym;
244
245           if(tux.key_event(key, UP))
246             break;
247
248           switch(key)
249             {
250             case SDLK_p:
251               if(!show_menu)
252                 {
253                   if(game_pause)
254                     {
255                       game_pause = 0;
256                       st_pause_ticks_stop();
257                     }
258                   else
259                     {
260                       game_pause = 1;
261                       st_pause_ticks_start();
262                     }
263                 }
264               break;
265             case SDLK_TAB:
266               if(debug_mode)
267                 {
268                   tux.size = !tux.size;
269                   if(tux.size == BIG)
270                     {
271                       tux.base.height = 64;
272                     }
273                   else
274                     tux.base.height = 32;
275                 }
276               break;
277             case SDLK_END:
278               if(debug_mode)
279                 distros += 50;
280               break;
281             case SDLK_SPACE:
282               if(debug_mode)
283                 next_level = 1;
284               break;
285             case SDLK_DELETE:
286               if(debug_mode)
287                 tux.got_coffee = 1;
288               break;
289             case SDLK_INSERT:
290               if(debug_mode)
291                 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
292               break;
293             case SDLK_l:
294               if(debug_mode)
295                 --tux.lives;
296               break;
297             case SDLK_s:
298               if(debug_mode)
299                 score += 1000;
300             case SDLK_f:
301               if(debug_fps)
302                 debug_fps = false;
303               else
304                 debug_fps = true;
305               break;
306             default:
307               break;
308             }
309           break;
310
311         case SDL_JOYAXISMOTION:
312           switch(event.jaxis.axis)
313             {
314             case JOY_X:
315               if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
316                 {
317                   tux.input.left  = DOWN;
318                   tux.input.right = UP;
319                 }
320               else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
321                 {
322                   tux.input.left  = UP;
323                   tux.input.right = DOWN;
324                 }
325               else
326                 {
327                   tux.input.left  = DOWN;
328                   tux.input.right = DOWN;
329                 }
330               break;
331             case JOY_Y:
332               if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
333                 tux.input.down = DOWN;
334               else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
335                 tux.input.down = UP;
336               else
337                 tux.input.down = UP;
338               
339               break;
340             default:
341               break;
342             }
343           break;
344         case SDL_JOYBUTTONDOWN:
345           if (event.jbutton.button == JOY_A)
346             tux.input.up = DOWN;
347           else if (event.jbutton.button == JOY_B)
348             tux.input.fire = DOWN;
349           break;
350         case SDL_JOYBUTTONUP:
351           if (event.jbutton.button == JOY_A)
352             tux.input.up = UP;
353           else if (event.jbutton.button == JOY_B)
354             tux.input.fire = UP;
355             
356           break;
357
358         default:
359           break;
360
361         }  /* switch */
362
363     } /* while */
364 }
365
366 int
367 GameSession::action()
368 {
369   if (tux.is_dead() || next_level)
370     {
371       /* Tux either died, or reached the end of a level! */
372
373       halt_music();
374
375
376       if (next_level)
377         {
378           /* End of a level! */
379           level++;
380           next_level = 0;
381           if(st_gl_mode != ST_GL_TEST)
382             {
383               drawresultscreen();
384             }
385           else
386             {
387               level_free_gfx();
388               current_level.cleanup();
389               level_free_song();
390               unloadshared();
391               world.arrays_free();
392               return(0);
393             }
394           tux.level_begin();
395         }
396       else
397         {
398           tux.is_dying();
399
400           /* No more lives!? */
401
402           if (tux.lives < 0)
403             {
404               if(st_gl_mode != ST_GL_TEST)
405                 drawendscreen();
406
407               if(st_gl_mode != ST_GL_TEST)
408                 {
409                   if (score > hs_score)
410                     save_hs(score);
411                 }
412               level_free_gfx();
413               current_level.cleanup();
414               level_free_song();
415               unloadshared();
416               world.arrays_free();
417               return(0);
418             } /* if (lives < 0) */
419         }
420
421       /* Either way, (re-)load the (next) level... */
422
423       tux.level_begin();
424       set_defaults();
425       current_level.cleanup();
426
427       if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
428         {
429           if(current_level.load(level_subset) != 0)
430             return 0;
431         }
432       else
433         {
434           if(current_level.load(level_subset,level) != 0)
435             return 0;
436         }
437
438       world.arrays_free();
439       activate_bad_guys(&current_level);
440       activate_particle_systems();
441       level_free_gfx();
442       current_level.load_gfx();
443       level_free_song();
444       current_level.load_song();
445       if(st_gl_mode != ST_GL_TEST)
446         levelintro();
447       start_timers();
448       /* Play music: */
449       play_current_music();
450     }
451
452   tux.action();
453
454   world.action();
455
456   /* update particle systems */
457   std::vector<ParticleSystem*>::iterator p;
458   for(p = world.particle_systems.begin(); p != world.particle_systems.end(); ++p)
459     {
460       (*p)->simulate(frame_ratio);
461     }
462
463   /* Handle all possible collisions. */
464   collision_handler();
465
466   return -1;
467 }
468
469 void 
470 GameSession::draw()
471 {
472   int y,x;
473
474   /* Draw screen: */
475   if(timer_check(&super_bkgd_timer))
476     texture_draw(&img_super_bkgd, 0, 0);
477   else
478     {
479       /* Draw the real background */
480       if(current_level.bkgd_image[0] != '\0')
481         {
482           int s = (int)scroll_x / 30;
483           texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
484           texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
485         }
486       else
487         {
488           clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
489         }
490     }
491
492   /* Draw particle systems (background) */
493   std::vector<ParticleSystem*>::iterator p;
494   for(p = world.particle_systems.begin(); p != world.particle_systems.end(); ++p)
495     {
496       (*p)->draw(scroll_x, 0, 0);
497     }
498
499   /* Draw background: */
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   world.draw();
520
521   for (unsigned int i = 0; i < world.broken_bricks.size(); ++i)
522     broken_brick_draw(&world.broken_bricks[i]);
523
524   /* Draw foreground: */
525   for (y = 0; y < 15; ++y)
526     {
527       for (x = 0; x < 21; ++x)
528         {
529           drawshape(32*x - fmodf(scroll_x, 32), y * 32,
530                     current_level.fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
531         }
532     }
533
534   /* Draw particle systems (foreground) */
535   for(p = world.particle_systems.begin(); p != world.particle_systems.end(); ++p)
536     {
537       (*p)->draw(scroll_x, 0, 1);
538     }
539
540   drawstatus();
541
542   if(game_pause)
543     {
544       int x = screen->h / 20;
545       for(int i = 0; i < x; ++i)
546         {
547           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);
548         }
549       fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
550       text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
551     }
552
553   if(show_menu)
554   {
555     menu_process_current();
556     mouse_cursor->draw();
557   }
558
559   /* (Update it all!) */
560   updatescreen();
561 }
562
563
564 int
565 GameSession::run()
566 {
567   current_ = this;
568   
569   int  fps_cnt;
570   bool jump;
571   bool done;
572
573   /* --- MAIN GAME LOOP!!! --- */
574   jump = false;
575   done = false;
576   quit = 0;
577   global_frame_counter = 0;
578   game_pause = 0;
579   timer_init(&fps_timer,true);
580   timer_init(&frame_timer,true);
581   last_update_time = st_get_ticks();
582   fps_cnt = 0;
583
584   /* Clear screen: */
585   clearscreen(0, 0, 0);
586   updatescreen();
587
588   /* Play music: */
589   play_current_music();
590
591   while (SDL_PollEvent(&event))
592   {}
593
594   draw();
595   do
596     {
597       jump = false;
598
599       /* Calculate the movement-factor */
600       frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
601       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
602         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
603
604       if(!timer_check(&frame_timer))
605         {
606           timer_start(&frame_timer,25);
607           ++global_frame_counter;
608         }
609
610       /* Handle events: */
611
612       tux.input.old_fire = tux.input.fire;
613
614       process_events();
615
616       if(show_menu)
617         {
618           if(current_menu == game_menu)
619             {
620               switch (game_menu->check())
621                 {
622                 case 2:
623                   st_pause_ticks_stop();
624                   break;
625                 case 3:
626                   update_load_save_game_menu(save_game_menu, false);
627                   break;
628                 case 4:
629                   update_load_save_game_menu(load_game_menu, true);
630                   break;
631                 case 7:
632                   st_pause_ticks_stop();
633                   done = true;
634                   break;
635                 }
636             }
637           else if(current_menu == options_menu)
638             {
639               process_options_menu();
640             }
641           else if(current_menu == save_game_menu )
642             {
643               process_save_game_menu();
644             }
645           else if(current_menu == load_game_menu )
646             {
647               process_load_game_menu();
648             }
649         }
650
651
652       /* Handle actions: */
653
654       if(!game_pause && !show_menu)
655         {
656           /*float z = frame_ratio;
657             frame_ratio = 1;
658             while(z >= 1)
659             {*/
660           if (action() == 0)
661             {
662               /* == 0: no more lives */
663               /* == -1: continues */
664               return 0;
665             }
666           /*  --z;
667                      }*/
668         }
669       else
670         {
671           ++pause_menu_frame;
672           SDL_Delay(50);
673         }
674
675       if(debug_mode && debug_fps)
676         SDL_Delay(60);
677
678       /*Draw the current scene to the screen */
679       /*If the machine running the game is too slow
680         skip the drawing of the frame (so the calculations are more precise and
681         the FPS aren't affected).*/
682       /*if( ! fps_fps < 50.0 )
683         game_draw();
684         else
685         jump = true;*/ /*FIXME: Implement this tweak right.*/
686       draw();
687
688       /* Time stops in pause mode */
689       if(game_pause || show_menu )
690         {
691           continue;
692         }
693
694       /* Set the time of the last update and the time of the current update */
695       last_update_time = update_time;
696       update_time = st_get_ticks();
697
698       /* Pause till next frame, if the machine running the game is too fast: */
699       /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
700          the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
701       if(last_update_time >= update_time - 12 && !jump) {
702         SDL_Delay(10);
703         update_time = st_get_ticks();
704       }
705       /*if((update_time - last_update_time) < 10)
706         SDL_Delay((11 - (update_time - last_update_time))/2);*/
707
708
709
710       /* Handle time: */
711
712       if (timer_check(&time_left))
713         {
714           /* are we low on time ? */
715           if ((timer_get_left(&time_left) < TIME_WARNING)
716               && (get_current_music() != HURRYUP_MUSIC))     /* play the fast music */
717             {
718               set_current_music(HURRYUP_MUSIC);
719               play_current_music();
720             }
721
722         }
723       else
724         tux.kill(KILL);
725
726
727       /* Calculate frames per second */
728       if(show_fps)
729         {
730           ++fps_cnt;
731           fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
732
733           if(!timer_check(&fps_timer))
734             {
735               timer_start(&fps_timer,1000);
736               fps_cnt = 0;
737             }
738         }
739
740     }
741   while (!done && !quit);
742
743   halt_music();
744
745   level_free_gfx();
746   current_level.cleanup();
747   level_free_song();
748   unloadshared();
749   world.arrays_free();
750
751   game_started = false;
752
753   return(quit);
754 }
755
756 /* Load graphics/sounds shared between all levels: */
757 void loadshared()
758 {
759   int i;
760
761   /* Tuxes: */
762   texture_load(&smalltux_stand_left, datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
763   texture_load(&smalltux_stand_right, datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
764
765   texture_load(&smalltux_jump_left, datadir + "/images/shared/smalltux-jump-left.png", USE_ALPHA);
766   texture_load(&smalltux_jump_right, datadir + "/images/shared/smalltux-jump-right.png", USE_ALPHA);
767
768   tux_right.resize(8);
769   texture_load(&tux_right[0], datadir + "/images/shared/smalltux-right-1.png", USE_ALPHA);
770   texture_load(&tux_right[1], datadir + "/images/shared/smalltux-right-2.png", USE_ALPHA);
771   texture_load(&tux_right[2], datadir + "/images/shared/smalltux-right-3.png", USE_ALPHA);
772   texture_load(&tux_right[3], datadir + "/images/shared/smalltux-right-4.png", USE_ALPHA);
773   texture_load(&tux_right[4], datadir + "/images/shared/smalltux-right-5.png", USE_ALPHA);
774   texture_load(&tux_right[5], datadir + "/images/shared/smalltux-right-6.png", USE_ALPHA);
775   texture_load(&tux_right[6], datadir + "/images/shared/smalltux-right-7.png", USE_ALPHA);
776   texture_load(&tux_right[7], datadir + "/images/shared/smalltux-right-8.png", USE_ALPHA);
777
778   tux_left.resize(8);
779   texture_load(&tux_left[0], datadir + "/images/shared/smalltux-left-1.png", USE_ALPHA);
780   texture_load(&tux_left[1], datadir + "/images/shared/smalltux-left-2.png", USE_ALPHA);
781   texture_load(&tux_left[2], datadir + "/images/shared/smalltux-left-3.png", USE_ALPHA);
782   texture_load(&tux_left[3], datadir + "/images/shared/smalltux-left-4.png", USE_ALPHA);
783   texture_load(&tux_left[4], datadir + "/images/shared/smalltux-left-5.png", USE_ALPHA);
784   texture_load(&tux_left[5], datadir + "/images/shared/smalltux-left-6.png", USE_ALPHA);
785   texture_load(&tux_left[6], datadir + "/images/shared/smalltux-left-7.png", USE_ALPHA);
786   texture_load(&tux_left[7], datadir + "/images/shared/smalltux-left-8.png", USE_ALPHA);
787
788   texture_load(&firetux_right[0], datadir + "/images/shared/firetux-right-0.png", USE_ALPHA);
789   texture_load(&firetux_right[1], datadir + "/images/shared/firetux-right-1.png", USE_ALPHA);
790   texture_load(&firetux_right[2], datadir + "/images/shared/firetux-right-2.png", USE_ALPHA);
791
792   texture_load(&firetux_left[0], datadir + "/images/shared/firetux-left-0.png", USE_ALPHA);
793   texture_load(&firetux_left[1], datadir + "/images/shared/firetux-left-1.png", USE_ALPHA);
794   texture_load(&firetux_left[2], datadir + "/images/shared/firetux-left-2.png", USE_ALPHA);
795
796
797   texture_load(&cape_right[0], datadir + "/images/shared/cape-right-0.png",
798                USE_ALPHA);
799
800   texture_load(&cape_right[1], datadir + "/images/shared/cape-right-1.png",
801                USE_ALPHA);
802
803   texture_load(&cape_left[0], datadir + "/images/shared/cape-left-0.png",
804                USE_ALPHA);
805
806   texture_load(&cape_left[1], datadir + "/images/shared/cape-left-1.png",
807                USE_ALPHA);
808
809   texture_load(&bigtux_right[0], datadir + "/images/shared/bigtux-right-0.png",
810                USE_ALPHA);
811
812   texture_load(&bigtux_right[1], datadir + "/images/shared/bigtux-right-1.png",
813                USE_ALPHA);
814
815   texture_load(&bigtux_right[2], datadir + "/images/shared/bigtux-right-2.png",
816                USE_ALPHA);
817
818   texture_load(&bigtux_right_jump, datadir + "/images/shared/bigtux-right-jump.png", USE_ALPHA);
819
820   texture_load(&bigtux_left[0], datadir + "/images/shared/bigtux-left-0.png",
821                USE_ALPHA);
822
823   texture_load(&bigtux_left[1], datadir + "/images/shared/bigtux-left-1.png",
824                USE_ALPHA);
825
826   texture_load(&bigtux_left[2], datadir + "/images/shared/bigtux-left-2.png",
827                USE_ALPHA);
828
829   texture_load(&bigtux_left_jump, datadir + "/images/shared/bigtux-left-jump.png", USE_ALPHA);
830
831   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
832                USE_ALPHA);
833
834   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
835                USE_ALPHA);
836
837   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
838                USE_ALPHA);
839
840   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
841                USE_ALPHA);
842
843   texture_load(&bigfiretux_right[0], datadir + "/images/shared/bigfiretux-right-0.png",
844                USE_ALPHA);
845
846   texture_load(&bigfiretux_right[1], datadir + "/images/shared/bigfiretux-right-1.png",
847                USE_ALPHA);
848
849   texture_load(&bigfiretux_right[2], datadir + "/images/shared/bigfiretux-right-2.png",
850                USE_ALPHA);
851
852   texture_load(&bigfiretux_right_jump, datadir + "/images/shared/bigfiretux-right-jump.png", USE_ALPHA);
853
854   texture_load(&bigfiretux_left[0], datadir + "/images/shared/bigfiretux-left-0.png",
855                USE_ALPHA);
856
857   texture_load(&bigfiretux_left[1], datadir + "/images/shared/bigfiretux-left-1.png",
858                USE_ALPHA);
859
860   texture_load(&bigfiretux_left[2], datadir + "/images/shared/bigfiretux-left-2.png",
861                USE_ALPHA);
862
863   texture_load(&bigfiretux_left_jump, datadir + "/images/shared/bigfiretux-left-jump.png", USE_ALPHA);
864
865   texture_load(&bigcape_right[0], datadir + "/images/shared/bigcape-right-0.png",
866                USE_ALPHA);
867
868   texture_load(&bigcape_right[1], datadir + "/images/shared/bigcape-right-1.png",
869                USE_ALPHA);
870
871   texture_load(&bigcape_left[0], datadir + "/images/shared/bigcape-left-0.png",
872                USE_ALPHA);
873
874   texture_load(&bigcape_left[1], datadir + "/images/shared/bigcape-left-1.png",
875                USE_ALPHA);
876
877
878   texture_load(&ducktux_right, datadir +
879                "/images/shared/ducktux-right.png",
880                USE_ALPHA);
881
882   texture_load(&ducktux_left, datadir +
883                "/images/shared/ducktux-left.png",
884                USE_ALPHA);
885
886   texture_load(&skidtux_right, datadir +
887                "/images/shared/skidtux-right.png",
888                USE_ALPHA);
889
890   texture_load(&skidtux_left, datadir +
891                "/images/shared/skidtux-left.png",
892                USE_ALPHA);
893
894   texture_load(&duckfiretux_right, datadir +
895                "/images/shared/duckfiretux-right.png",
896                USE_ALPHA);
897
898   texture_load(&duckfiretux_left, datadir +
899                "/images/shared/duckfiretux-left.png",
900                USE_ALPHA);
901
902   texture_load(&skidfiretux_right, datadir +
903                "/images/shared/skidfiretux-right.png",
904                USE_ALPHA);
905
906   texture_load(&skidfiretux_left, datadir +
907                "/images/shared/skidfiretux-left.png",
908                USE_ALPHA);
909
910
911   /* Boxes: */
912
913   texture_load(&img_box_full, datadir + "/images/shared/box-full.png",
914                IGNORE_ALPHA);
915   texture_load(&img_box_empty, datadir + "/images/shared/box-empty.png",
916                IGNORE_ALPHA);
917
918
919   /* Water: */
920
921
922   texture_load(&img_water, datadir + "/images/shared/water.png", IGNORE_ALPHA);
923
924   texture_load(&img_waves[0], datadir + "/images/shared/waves-0.png",
925                USE_ALPHA);
926
927   texture_load(&img_waves[1], datadir + "/images/shared/waves-1.png",
928                USE_ALPHA);
929
930   texture_load(&img_waves[2], datadir + "/images/shared/waves-2.png",
931                USE_ALPHA);
932
933
934   /* Pole: */
935
936   texture_load(&img_pole, datadir + "/images/shared/pole.png", USE_ALPHA);
937   texture_load(&img_poletop, datadir + "/images/shared/poletop.png",
938                USE_ALPHA);
939
940
941   /* Flag: */
942
943   texture_load(&img_flag[0], datadir + "/images/shared/flag-0.png",
944                USE_ALPHA);
945   texture_load(&img_flag[1], datadir + "/images/shared/flag-1.png",
946                USE_ALPHA);
947
948
949   /* Cloud: */
950
951   texture_load(&img_cloud[0][0], datadir + "/images/shared/cloud-00.png",
952                USE_ALPHA);
953
954   texture_load(&img_cloud[0][1], datadir + "/images/shared/cloud-01.png",
955                USE_ALPHA);
956
957   texture_load(&img_cloud[0][2], datadir + "/images/shared/cloud-02.png",
958                USE_ALPHA);
959
960   texture_load(&img_cloud[0][3], datadir + "/images/shared/cloud-03.png",
961                USE_ALPHA);
962
963
964   texture_load(&img_cloud[1][0], datadir + "/images/shared/cloud-10.png",
965                USE_ALPHA);
966
967   texture_load(&img_cloud[1][1], datadir + "/images/shared/cloud-11.png",
968                USE_ALPHA);
969
970   texture_load(&img_cloud[1][2], datadir + "/images/shared/cloud-12.png",
971                USE_ALPHA);
972
973   texture_load(&img_cloud[1][3], datadir + "/images/shared/cloud-13.png",
974                USE_ALPHA);
975
976
977   /* Bad guys: */
978   load_badguy_gfx();
979
980   /* Upgrades: */
981
982   texture_load(&img_mints, datadir + "/images/shared/mints.png", USE_ALPHA);
983   texture_load(&img_coffee, datadir + "/images/shared/coffee.png", USE_ALPHA);
984
985
986   /* Weapons: */
987
988   texture_load(&img_bullet, datadir + "/images/shared/bullet.png", USE_ALPHA);
989
990   texture_load(&img_red_glow, datadir + "/images/shared/red-glow.png",
991                USE_ALPHA);
992
993
994
995   /* Distros: */
996
997   texture_load(&img_distro[0], datadir + "/images/shared/distro-0.png",
998                USE_ALPHA);
999
1000   texture_load(&img_distro[1], datadir + "/images/shared/distro-1.png",
1001                USE_ALPHA);
1002
1003   texture_load(&img_distro[2], datadir + "/images/shared/distro-2.png",
1004                USE_ALPHA);
1005
1006   texture_load(&img_distro[3], datadir + "/images/shared/distro-3.png",
1007                USE_ALPHA);
1008
1009
1010   /* Tux life: */
1011
1012   texture_load(&tux_life, datadir + "/images/shared/tux-life.png",
1013                USE_ALPHA);
1014
1015   /* Herring: */
1016
1017   texture_load(&img_golden_herring, datadir + "/images/shared/golden-herring.png",
1018                USE_ALPHA);
1019
1020
1021   /* Super background: */
1022
1023   texture_load(&img_super_bkgd, datadir + "/images/shared/super-bkgd.png",
1024                IGNORE_ALPHA);
1025
1026
1027   /* Sound effects: */
1028
1029   /* if (use_sound) // this will introduce SERIOUS bugs here ! because "load_sound"
1030                     // initialize sounds[i] with the correct pointer's value:
1031                     // NULL or something else. And it will be dangerous to
1032                     // play with not-initialized pointers.
1033                     // This is also true with if (use_music)
1034                     Send a mail to me: neoneurone@users.sf.net, if you have another opinion. :)
1035   */
1036   for (i = 0; i < NUM_SOUNDS; i++)
1037     sounds[i] = load_sound(datadir + soundfilenames[i]);
1038
1039   /* Herring song */
1040   herring_song = load_song(datadir + "/music/SALCON.MOD");
1041 }
1042
1043
1044 /* Free shared data: */
1045
1046 void unloadshared(void)
1047 {
1048   int i;
1049
1050   for (i = 0; i < 3; i++)
1051     {
1052       texture_free(&tux_right[i]);
1053       texture_free(&tux_left[i]);
1054       texture_free(&bigtux_right[i]);
1055       texture_free(&bigtux_left[i]);
1056     }
1057
1058   texture_free(&bigtux_right_jump);
1059   texture_free(&bigtux_left_jump);
1060
1061   for (i = 0; i < 2; i++)
1062     {
1063       texture_free(&cape_right[i]);
1064       texture_free(&cape_left[i]);
1065       texture_free(&bigcape_right[i]);
1066       texture_free(&bigcape_left[i]);
1067     }
1068
1069   texture_free(&ducktux_left);
1070   texture_free(&ducktux_right);
1071
1072   texture_free(&skidtux_left);
1073   texture_free(&skidtux_right);
1074
1075   free_badguy_gfx();
1076
1077   texture_free(&img_box_full);
1078   texture_free(&img_box_empty);
1079
1080   texture_free(&img_water);
1081   for (i = 0; i < 3; i++)
1082     texture_free(&img_waves[i]);
1083
1084   texture_free(&img_pole);
1085   texture_free(&img_poletop);
1086
1087   for (i = 0; i < 2; i++)
1088     texture_free(&img_flag[i]);
1089
1090   texture_free(&img_mints);
1091   texture_free(&img_coffee);
1092
1093   for (i = 0; i < 4; i++)
1094     {
1095       texture_free(&img_distro[i]);
1096       texture_free(&img_cloud[0][i]);
1097       texture_free(&img_cloud[1][i]);
1098     }
1099
1100   texture_free(&img_golden_herring);
1101
1102   for (i = 0; i < NUM_SOUNDS; i++)
1103     free_chunk(sounds[i]);
1104
1105   /* free the herring song */
1106   free_music( herring_song );
1107 }
1108
1109
1110 /* Draw a tile on the screen: */
1111
1112 void drawshape(float x, float y, unsigned int c, Uint8 alpha)
1113 {
1114   if (c != 0)
1115     {
1116       Tile* ptile = TileManager::instance()->get(c);
1117       if(ptile)
1118         {
1119           if(ptile->images.size() > 1)
1120             {
1121               texture_draw(&ptile->images[( ((global_frame_counter*25) / ptile->anim_speed) % (ptile->images.size()))],x,y, alpha);
1122             }
1123           else if (ptile->images.size() == 1)
1124             {
1125               texture_draw(&ptile->images[0],x,y, alpha);
1126             }
1127           else
1128             {
1129               //printf("Tile not dravable %u\n", c);
1130             }
1131         }
1132     }
1133 }
1134
1135 /* Bounce a brick: */
1136 void bumpbrick(float x, float y)
1137 {
1138   world.add_bouncy_brick(((int)(x + 1) / 32) * 32,
1139                          (int)(y / 32) * 32);
1140
1141   play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
1142 }
1143
1144 /* (Status): */
1145 void drawstatus(void)
1146 {
1147   char str[60];
1148
1149   sprintf(str, "%d", score);
1150   text_draw(&white_text, "SCORE", 0, 0, 1);
1151   text_draw(&gold_text, str, 96, 0, 1);
1152
1153   if(st_gl_mode != ST_GL_TEST)
1154     {
1155       sprintf(str, "%d", hs_score);
1156       text_draw(&white_text, "HIGH", 0, 20, 1);
1157       text_draw(&gold_text, str, 96, 20, 1);
1158     }
1159   else
1160     {
1161       text_draw(&white_text,"Press ESC To Return",0,20,1);
1162     }
1163
1164   if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
1165     {
1166       sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
1167       text_draw(&white_text, "TIME", 224, 0, 1);
1168       text_draw(&gold_text, str, 304, 0, 1);
1169     }
1170
1171   sprintf(str, "%d", distros);
1172   text_draw(&white_text, "DISTROS", screen->h, 0, 1);
1173   text_draw(&gold_text, str, 608, 0, 1);
1174
1175   text_draw(&white_text, "LIVES", screen->h, 20, 1);
1176
1177   if(show_fps)
1178     {
1179       sprintf(str, "%2.1f", fps_fps);
1180       text_draw(&white_text, "FPS", screen->h, 40, 1);
1181       text_draw(&gold_text, str, screen->h + 60, 40, 1);
1182     }
1183
1184   for(int i=0; i < tux.lives; ++i)
1185     {
1186       texture_draw(&tux_life,565+(18*i),20);
1187     }
1188 }
1189
1190
1191 void drawendscreen(void)
1192 {
1193   char str[80];
1194
1195   clearscreen(0, 0, 0);
1196
1197   text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
1198
1199   sprintf(str, "SCORE: %d", score);
1200   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1201
1202   sprintf(str, "DISTROS: %d", distros);
1203   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1204
1205   flipscreen();
1206   
1207   SDL_Event event;
1208   wait_for_event(event,2000,5000,true);
1209 }
1210
1211 void drawresultscreen(void)
1212 {
1213   char str[80];
1214
1215   clearscreen(0, 0, 0);
1216
1217   text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
1218
1219   sprintf(str, "SCORE: %d", score);
1220   text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
1221
1222   sprintf(str, "DISTROS: %d", distros);
1223   text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
1224
1225   flipscreen();
1226   
1227   SDL_Event event;
1228   wait_for_event(event,2000,5000,true);
1229 }
1230
1231 void
1232 GameSession::savegame(int slot)
1233 {
1234   char savefile[1024];
1235   FILE* fi;
1236   unsigned int ui;
1237
1238   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1239
1240   fi = fopen(savefile, "wb");
1241
1242   if (fi == NULL)
1243     {
1244       fprintf(stderr, "Warning: I could not open the slot file ");
1245     }
1246   else
1247     {
1248       fputs(level_subset, fi);
1249       fputs("\n", fi);
1250       fwrite(&level,sizeof(int),1,fi);
1251       fwrite(&score,sizeof(int),1,fi);
1252       fwrite(&distros,sizeof(int),1,fi);
1253       fwrite(&scroll_x,sizeof(float),1,fi);
1254       fwrite(&tux,sizeof(Player),1,fi);
1255       timer_fwrite(&tux.invincible_timer,fi);
1256       timer_fwrite(&tux.skidding_timer,fi);
1257       timer_fwrite(&tux.safe_timer,fi);
1258       timer_fwrite(&tux.frame_timer,fi);
1259       timer_fwrite(&time_left,fi);
1260       ui = st_get_ticks();
1261       fwrite(&ui,sizeof(int),1,fi);
1262     }
1263   fclose(fi);
1264
1265 }
1266
1267 void
1268 GameSession::loadgame(int slot)
1269 {
1270   char savefile[1024];
1271   char str[100];
1272   FILE* fi;
1273   unsigned int ui;
1274
1275   sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
1276
1277   fi = fopen(savefile, "rb");
1278
1279   if (fi == NULL)
1280     {
1281       fprintf(stderr, "Warning: I could not open the slot file ");
1282
1283     }
1284   else
1285     {
1286       fgets(str, 100, fi);
1287       strcpy(level_subset, str);
1288       level_subset[strlen(level_subset)-1] = '\0';
1289       fread(&level,sizeof(int),1,fi);
1290
1291       set_defaults();
1292       current_level.cleanup();
1293       if(current_level.load(level_subset,level) != 0)
1294         exit(1);
1295       world.arrays_free();
1296       activate_bad_guys(&current_level);
1297       activate_particle_systems();
1298       level_free_gfx();
1299       current_level.load_gfx();
1300       level_free_song();
1301       current_level.load_song();
1302       levelintro();
1303       update_time = st_get_ticks();
1304
1305       fread(&score,   sizeof(int),1,fi);
1306       fread(&distros, sizeof(int),1,fi);
1307       fread(&scroll_x,sizeof(float),1,fi);
1308       fread(&tux,     sizeof(Player), 1, fi);
1309       timer_fread(&tux.invincible_timer,fi);
1310       timer_fread(&tux.skidding_timer,fi);
1311       timer_fread(&tux.safe_timer,fi);
1312       timer_fread(&tux.frame_timer,fi);
1313       timer_fread(&time_left,fi);
1314       fread(&ui,sizeof(int),1,fi);
1315       fclose(fi);
1316     }
1317
1318 }
1319
1320 std::string slotinfo(int slot)
1321 {
1322   FILE* fi;
1323   char slotfile[1024];
1324   char tmp[200];
1325   char str[5];
1326   int slot_level;
1327   sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
1328
1329   fi = fopen(slotfile, "rb");
1330
1331   sprintf(tmp,"Slot %d - ",slot);
1332
1333   if (fi == NULL)
1334     {
1335       strcat(tmp,"Free");
1336     }
1337   else
1338     {
1339       fgets(str, 100, fi);
1340       str[strlen(str)-1] = '\0';
1341       strcat(tmp, str);
1342       strcat(tmp, " / Level:");
1343       fread(&slot_level,sizeof(int),1,fi);
1344       sprintf(str,"%d",slot_level);
1345       strcat(tmp,str);
1346       fclose(fi);
1347     }
1348
1349   return tmp;
1350 }
1351