6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
25 #include <sys/types.h>
34 #include "high_scores.h"
42 #include "collision.h"
44 #include "particlesystem.h"
45 #include "resources.h"
47 GameSession* GameSession::current_ = 0;
55 GameSession::GameSession()
61 GameSession::GameSession(const std::string& filename)
65 //assert(!"Don't call me");
68 world = new World; // &::global_world;
70 timer_init(&fps_timer, true);
71 timer_init(&frame_timer, true);
73 world->load(filename);
76 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
84 world = new World; // &::global_world;
86 timer_init(&fps_timer, true);
87 timer_init(&frame_timer, true);
93 world->set_defaults();
95 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
97 if (world->load(subset))
102 if(world->load(subset, levelnb) != 0)
106 world->get_level()->load_gfx();
109 world->activate_bad_guys();
110 world->activate_particle_systems();
111 world->get_level()->load_song();
113 if(st_gl_mode != ST_GL_TEST)
116 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
119 timer_init(&time_left,true);
122 if(st_gl_mode == ST_GL_LOAD_GAME)
126 GameSession::~GameSession()
132 GameSession::levelintro(void)
134 Player& tux = *world->get_tux();
138 clearscreen(0, 0, 0);
140 sprintf(str, "LEVEL %d", levelnb);
141 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
143 sprintf(str, "%s", world->get_level()->name.c_str());
144 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
146 sprintf(str, "TUX x %d", tux.lives);
147 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
152 wait_for_event(event,1000,3000,true);
157 GameSession::start_timers()
159 timer_start(&time_left, world->get_level()->time_left*1000);
160 st_pause_ticks_init();
161 update_time = st_get_ticks();
165 GameSession::process_events()
167 Player& tux = *world->get_tux();
170 while (SDL_PollEvent(&event))
172 /* Check for menu-events, if the menu is shown */
178 case SDL_QUIT: /* Quit event - quit: */
181 case SDL_KEYDOWN: /* A keypress! */
183 SDLKey key = event.key.keysym.sym;
185 if(tux.key_event(key,DOWN))
190 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
193 if(st_gl_mode == ST_GL_TEST)
197 Menu::set_current(game_menu);
199 st_pause_ticks_stop();
203 Menu::set_current(game_menu);
205 st_pause_ticks_start();
214 case SDL_KEYUP: /* A keyrelease! */
216 SDLKey key = event.key.keysym.sym;
218 if(tux.key_event(key, UP))
229 st_pause_ticks_stop();
234 st_pause_ticks_start();
241 tux.size = !tux.size;
244 tux.base.height = 64;
247 tux.base.height = 32;
252 player_status.distros += 50;
256 player_status.next_level = 1;
264 timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME);
272 player_status.score += 1000;
285 case SDL_JOYAXISMOTION:
286 switch(event.jaxis.axis)
289 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
291 tux.input.left = DOWN;
292 tux.input.right = UP;
294 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
297 tux.input.right = DOWN;
301 tux.input.left = DOWN;
302 tux.input.right = DOWN;
306 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
307 tux.input.down = DOWN;
308 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
318 case SDL_JOYBUTTONDOWN:
319 if (event.jbutton.button == JOY_A)
321 else if (event.jbutton.button == JOY_B)
322 tux.input.fire = DOWN;
324 case SDL_JOYBUTTONUP:
325 if (event.jbutton.button == JOY_A)
327 else if (event.jbutton.button == JOY_B)
341 GameSession::action(double frame_ratio)
343 Player& tux = *world->get_tux();
345 if (tux.is_dead() || player_status.next_level)
347 /* Tux either died, or reached the end of a level! */
350 if (player_status.next_level)
352 /* End of a level! */
354 player_status.next_level = 0;
355 if(st_gl_mode != ST_GL_TEST)
361 world->get_level()->free_gfx();
362 world->get_level()->cleanup();
363 world->get_level()->free_song();
364 world->arrays_free();
375 /* No more lives!? */
379 if(st_gl_mode != ST_GL_TEST)
382 if(st_gl_mode != ST_GL_TEST)
384 if (player_status.score > hs_score)
385 save_hs(player_status.score);
388 world->get_level()->free_gfx();
389 world->get_level()->cleanup();
390 world->get_level()->free_song();
391 world->arrays_free();
395 } /* if (lives < 0) */
398 /* Either way, (re-)load the (next) level... */
400 world->set_defaults();
402 world->get_level()->cleanup();
404 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
406 if(world->get_level()->load(subset) != 0)
411 if(world->get_level()->load(subset, levelnb) != 0)
415 world->arrays_free();
416 world->activate_bad_guys();
417 world->activate_particle_systems();
419 world->get_level()->free_gfx();
420 world->get_level()->load_gfx();
421 world->get_level()->free_song();
422 world->get_level()->load_song();
424 if(st_gl_mode != ST_GL_TEST)
428 play_current_music();
431 tux.action(frame_ratio);
433 world->action(frame_ratio);
446 int x = screen->h / 20;
447 for(int i = 0; i < x; ++i)
449 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);
451 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
452 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
457 menu_process_current();
458 mouse_cursor->draw();
468 Player& tux = *world->get_tux();
474 global_frame_counter = 0;
476 timer_init(&fps_timer,true);
477 timer_init(&frame_timer,true);
478 last_update_time = st_get_ticks();
482 clearscreen(0, 0, 0);
486 play_current_music();
488 // Eat unneeded events
490 while (SDL_PollEvent(&event)) {}
496 while (!done && !quit)
498 /* Calculate the movement-factor */
499 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
500 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
501 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
503 if(!timer_check(&frame_timer))
505 timer_start(&frame_timer,25);
506 ++global_frame_counter;
510 tux.input.old_fire = tux.input.fire;
516 if(current_menu == game_menu)
518 switch (game_menu->check())
521 st_pause_ticks_stop();
524 update_load_save_game_menu(save_game_menu, false);
527 update_load_save_game_menu(load_game_menu, true);
530 st_pause_ticks_stop();
535 else if(current_menu == options_menu)
537 process_options_menu();
539 else if(current_menu == save_game_menu )
541 process_save_game_menu();
543 else if(current_menu == load_game_menu )
545 process_load_game_menu();
550 /* Handle actions: */
552 if(!game_pause && !show_menu)
554 /*float z = frame_ratio;
558 if (action(frame_ratio) == 0)
560 /* == 0: no more lives */
561 /* == -1: continues */
573 if(debug_mode && debug_fps)
576 /*Draw the current scene to the screen */
577 /*If the machine running the game is too slow
578 skip the drawing of the frame (so the calculations are more precise and
579 the FPS aren't affected).*/
580 /*if( ! fps_fps < 50.0 )
583 jump = true;*/ /*FIXME: Implement this tweak right.*/
586 /* Time stops in pause mode */
587 if(game_pause || show_menu )
592 /* Set the time of the last update and the time of the current update */
593 last_update_time = update_time;
594 update_time = st_get_ticks();
596 /* Pause till next frame, if the machine running the game is too fast: */
597 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
598 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
599 if(last_update_time >= update_time - 12) {
601 update_time = st_get_ticks();
603 /*if((update_time - last_update_time) < 10)
604 SDL_Delay((11 - (update_time - last_update_time))/2);*/
607 if (timer_check(&time_left))
609 /* are we low on time ? */
610 if ((timer_get_left(&time_left) < TIME_WARNING)
611 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
613 set_current_music(HURRYUP_MUSIC);
614 play_current_music();
621 /* Calculate frames per second */
625 fps_fps = (1000.0 / (float)timer_get_gone(&fps_timer)) * (float)fps_cnt;
627 if(!timer_check(&fps_timer))
629 timer_start(&fps_timer,1000);
637 world->get_level()->free_gfx();
638 world->get_level()->cleanup();
639 world->get_level()->free_song();
642 world->arrays_free();
647 /* Bounce a brick: */
648 void bumpbrick(float x, float y)
650 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
653 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
658 GameSession::drawstatus()
660 Player& tux = *world->get_tux();
663 sprintf(str, "%d", player_status.score);
664 text_draw(&white_text, "SCORE", 0, 0, 1);
665 text_draw(&gold_text, str, 96, 0, 1);
667 if(st_gl_mode != ST_GL_TEST)
669 sprintf(str, "%d", hs_score);
670 text_draw(&white_text, "HIGH", 0, 20, 1);
671 text_draw(&gold_text, str, 96, 20, 1);
675 text_draw(&white_text,"Press ESC To Return",0,20,1);
678 if (timer_get_left(&time_left) > TIME_WARNING || (global_frame_counter % 10) < 5)
680 sprintf(str, "%d", timer_get_left(&time_left) / 1000 );
681 text_draw(&white_text, "TIME", 224, 0, 1);
682 text_draw(&gold_text, str, 304, 0, 1);
685 sprintf(str, "%d", player_status.distros);
686 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
687 text_draw(&gold_text, str, 608, 0, 1);
689 text_draw(&white_text, "LIVES", screen->h, 20, 1);
693 sprintf(str, "%2.1f", fps_fps);
694 text_draw(&white_text, "FPS", screen->h, 40, 1);
695 text_draw(&gold_text, str, screen->h + 60, 40, 1);
698 for(int i= 0; i < tux.lives; ++i)
700 texture_draw(&tux_life,565+(18*i),20);
705 GameSession::drawendscreen()
709 clearscreen(0, 0, 0);
711 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
713 sprintf(str, "SCORE: %d", player_status.score);
714 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
716 sprintf(str, "DISTROS: %d", player_status.distros);
717 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
722 wait_for_event(event,2000,5000,true);
726 GameSession::drawresultscreen(void)
730 clearscreen(0, 0, 0);
732 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
734 sprintf(str, "SCORE: %d", player_status.score);
735 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
737 sprintf(str, "DISTROS: %d", player_status.distros);
738 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
743 wait_for_event(event,2000,5000,true);
747 GameSession::savegame(int)
754 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
756 fi = fopen(savefile, "wb");
760 fprintf(stderr, "Warning: I could not open the slot file ");
764 fputs(level_subset, fi);
766 fwrite(&level,sizeof(int),1,fi);
767 fwrite(&score,sizeof(int),1,fi);
768 fwrite(&distros,sizeof(int),1,fi);
769 fwrite(&scroll_x,sizeof(float),1,fi);
770 //FIXME:fwrite(&tux,sizeof(Player),1,fi);
771 //FIXME:timer_fwrite(&tux.invincible_timer,fi);
772 //FIXME:timer_fwrite(&tux.skidding_timer,fi);
773 //FIXME:timer_fwrite(&tux.safe_timer,fi);
774 //FIXME:timer_fwrite(&tux.frame_timer,fi);
775 timer_fwrite(&time_left,fi);
777 fwrite(&ui,sizeof(int),1,fi);
784 GameSession::loadgame(int)
792 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
794 fi = fopen(savefile, "rb");
798 fprintf(stderr, "Warning: I could not open the slot file ");
804 strcpy(level_subset, str);
805 level_subset[strlen(level_subset)-1] = '\0';
806 fread(&level,sizeof(int),1,fi);
808 world->set_defaults();
809 world->get_level()->cleanup();
810 world->arrays_free();
811 world->get_level()->free_gfx();
812 world->get_level()->free_song();
814 if(world->get_level()->load(level_subset,level) != 0)
817 world->activate_bad_guys();
818 world->activate_particle_systems();
819 world->get_level()->load_gfx();
820 world->get_level()->load_song();
823 update_time = st_get_ticks();
825 fread(&score, sizeof(int),1,fi);
826 fread(&distros, sizeof(int),1,fi);
827 fread(&scroll_x,sizeof(float),1,fi);
828 //FIXME:fread(&tux, sizeof(Player), 1, fi);
829 //FIXME:timer_fread(&tux.invincible_timer,fi);
830 //FIXME:timer_fread(&tux.skidding_timer,fi);
831 //FIXME:timer_fread(&tux.safe_timer,fi);
832 //FIXME:timer_fread(&tux.frame_timer,fi);
833 timer_fread(&time_left,fi);
834 fread(&ui,sizeof(int),1,fi);
840 std::string slotinfo(int slot)
847 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
849 fi = fopen(slotfile, "rb");
851 sprintf(tmp,"Slot %d - ",slot);
860 str[strlen(str)-1] = '\0';
862 strcat(tmp, " / Level:");
863 fread(&slot_level,sizeof(int),1,fi);
864 sprintf(str,"%d",slot_level);