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");
71 frame_timer.init(true);
73 world->load(filename);
76 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
87 frame_timer.init(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();
108 world->activate_bad_guys();
109 world->activate_particle_systems();
110 world->get_level()->load_song();
112 if(st_gl_mode != ST_GL_TEST)
115 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
118 time_left.init(true);
121 if(st_gl_mode == ST_GL_LOAD_GAME)
125 GameSession::~GameSession()
131 GameSession::levelintro(void)
133 Player& tux = *world->get_tux();
137 clearscreen(0, 0, 0);
139 sprintf(str, "LEVEL %d", levelnb);
140 text_drawf(&blue_text, str, 0, 200, A_HMIDDLE, A_TOP, 1);
142 sprintf(str, "%s", world->get_level()->name.c_str());
143 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
145 sprintf(str, "TUX x %d", tux.lives);
146 text_drawf(&white_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
151 wait_for_event(event,1000,3000,true);
156 GameSession::start_timers()
158 time_left.start(world->get_level()->time_left*1000);
159 st_pause_ticks_init();
160 update_time = st_get_ticks();
164 GameSession::process_events()
166 Player& tux = *world->get_tux();
169 while (SDL_PollEvent(&event))
171 /* Check for menu-events, if the menu is shown */
173 current_menu->event(event);
177 case SDL_QUIT: /* Quit event - quit: */
180 case SDL_KEYDOWN: /* A keypress! */
182 SDLKey key = event.key.keysym.sym;
184 if(tux.key_event(key,DOWN))
189 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
192 if(st_gl_mode == ST_GL_TEST)
196 Menu::set_current(game_menu);
198 st_pause_ticks_stop();
202 Menu::set_current(game_menu);
204 st_pause_ticks_start();
213 case SDL_KEYUP: /* A keyrelease! */
215 SDLKey key = event.key.keysym.sym;
217 if(tux.key_event(key, UP))
228 st_pause_ticks_stop();
233 st_pause_ticks_start();
240 tux.size = !tux.size;
243 tux.base.height = 64;
246 tux.base.height = 32;
251 player_status.distros += 50;
255 player_status.next_level = 1;
263 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
271 player_status.score += 1000;
284 case SDL_JOYAXISMOTION:
285 switch(event.jaxis.axis)
288 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
290 tux.input.left = DOWN;
291 tux.input.right = UP;
293 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
296 tux.input.right = DOWN;
300 tux.input.left = DOWN;
301 tux.input.right = DOWN;
305 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
306 tux.input.down = DOWN;
307 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
317 case SDL_JOYBUTTONDOWN:
318 if (event.jbutton.button == JOY_A)
320 else if (event.jbutton.button == JOY_B)
321 tux.input.fire = DOWN;
323 case SDL_JOYBUTTONUP:
324 if (event.jbutton.button == JOY_A)
326 else if (event.jbutton.button == JOY_B)
340 GameSession::action(double frame_ratio)
342 Player& tux = *world->get_tux();
344 if (tux.is_dead() || player_status.next_level)
346 /* Tux either died, or reached the end of a level! */
349 if (player_status.next_level)
351 /* End of a level! */
353 player_status.next_level = 0;
354 if(st_gl_mode != ST_GL_TEST)
360 world->get_level()->free_gfx();
361 world->get_level()->cleanup();
362 world->get_level()->free_song();
363 world->arrays_free();
373 /* No more lives!? */
377 if(st_gl_mode != ST_GL_TEST)
380 if(st_gl_mode != ST_GL_TEST)
382 if (player_status.score > hs_score)
383 save_hs(player_status.score);
386 world->get_level()->free_gfx();
387 world->get_level()->cleanup();
388 world->get_level()->free_song();
389 world->arrays_free();
392 } /* if (lives < 0) */
395 /* Either way, (re-)load the (next) level... */
397 world->set_defaults();
399 world->get_level()->cleanup();
401 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
403 if(world->get_level()->load(subset) != 0)
408 if(world->get_level()->load(subset, levelnb) != 0)
412 world->arrays_free();
413 world->activate_bad_guys();
414 world->activate_particle_systems();
416 world->get_level()->free_gfx();
417 world->get_level()->load_gfx();
418 world->get_level()->free_song();
419 world->get_level()->load_song();
421 if(st_gl_mode != ST_GL_TEST)
425 play_current_music();
428 tux.action(frame_ratio);
430 world->action(frame_ratio);
443 int x = screen->h / 20;
444 for(int i = 0; i < x; ++i)
446 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);
448 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
449 text_drawf(&blue_text, "PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
454 menu_process_current();
455 mouse_cursor->draw();
465 Player& tux = *world->get_tux();
471 global_frame_counter = 0;
474 fps_timer.init(true);
475 frame_timer.init(true);
477 last_update_time = st_get_ticks();
481 clearscreen(0, 0, 0);
485 play_current_music();
487 // Eat unneeded events
489 while (SDL_PollEvent(&event)) {}
495 while (!done && !quit)
497 /* Calculate the movement-factor */
498 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
499 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
500 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
502 if(!frame_timer.check())
504 frame_timer.start(25);
505 ++global_frame_counter;
509 tux.input.old_fire = tux.input.fire;
515 if(current_menu == game_menu)
517 switch (game_menu->check())
520 st_pause_ticks_stop();
523 update_load_save_game_menu(save_game_menu, false);
526 update_load_save_game_menu(load_game_menu, true);
529 st_pause_ticks_stop();
534 else if(current_menu == options_menu)
536 process_options_menu();
538 else if(current_menu == save_game_menu )
540 process_save_game_menu();
542 else if(current_menu == load_game_menu )
544 process_load_game_menu();
549 /* Handle actions: */
551 if(!game_pause && !show_menu)
553 /*float z = frame_ratio;
557 if (action(frame_ratio) == 0)
559 /* == 0: no more lives */
560 /* == -1: continues */
572 if(debug_mode && debug_fps)
575 /*Draw the current scene to the screen */
576 /*If the machine running the game is too slow
577 skip the drawing of the frame (so the calculations are more precise and
578 the FPS aren't affected).*/
579 /*if( ! fps_fps < 50.0 )
582 jump = true;*/ /*FIXME: Implement this tweak right.*/
585 /* Time stops in pause mode */
586 if(game_pause || show_menu )
591 /* Set the time of the last update and the time of the current update */
592 last_update_time = update_time;
593 update_time = st_get_ticks();
595 /* Pause till next frame, if the machine running the game is too fast: */
596 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
597 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
598 if(last_update_time >= update_time - 12) {
600 update_time = st_get_ticks();
602 /*if((update_time - last_update_time) < 10)
603 SDL_Delay((11 - (update_time - last_update_time))/2);*/
606 if (time_left.check())
608 /* are we low on time ? */
609 if (time_left.get_left() < TIME_WARNING
610 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
612 set_current_music(HURRYUP_MUSIC);
613 play_current_music();
620 /* Calculate frames per second */
624 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
626 if(!fps_timer.check())
628 fps_timer.start(1000);
636 world->get_level()->free_gfx();
637 world->get_level()->cleanup();
638 world->get_level()->free_song();
640 world->arrays_free();
645 /* Bounce a brick: */
646 void bumpbrick(float x, float y)
648 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
651 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
656 GameSession::drawstatus()
658 Player& tux = *world->get_tux();
661 sprintf(str, "%d", player_status.score);
662 text_draw(&white_text, "SCORE", 0, 0, 1);
663 text_draw(&gold_text, str, 96, 0, 1);
665 if(st_gl_mode != ST_GL_TEST)
667 sprintf(str, "%d", hs_score);
668 text_draw(&white_text, "HIGH", 0, 20, 1);
669 text_draw(&gold_text, str, 96, 20, 1);
673 text_draw(&white_text,"Press ESC To Return",0,20,1);
676 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
678 sprintf(str, "%d", time_left.get_left() / 1000 );
679 text_draw(&white_text, "TIME", 224, 0, 1);
680 text_draw(&gold_text, str, 304, 0, 1);
683 sprintf(str, "%d", player_status.distros);
684 text_draw(&white_text, "DISTROS", screen->h, 0, 1);
685 text_draw(&gold_text, str, 608, 0, 1);
687 text_draw(&white_text, "LIVES", screen->h, 20, 1);
691 sprintf(str, "%2.1f", fps_fps);
692 text_draw(&white_text, "FPS", screen->h, 40, 1);
693 text_draw(&gold_text, str, screen->h + 60, 40, 1);
696 for(int i= 0; i < tux.lives; ++i)
698 texture_draw(&tux_life,565+(18*i),20);
703 GameSession::drawendscreen()
707 clearscreen(0, 0, 0);
709 text_drawf(&blue_text, "GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
711 sprintf(str, "SCORE: %d", player_status.score);
712 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
714 sprintf(str, "DISTROS: %d", player_status.distros);
715 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
720 wait_for_event(event,2000,5000,true);
724 GameSession::drawresultscreen(void)
728 clearscreen(0, 0, 0);
730 text_drawf(&blue_text, "Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
732 sprintf(str, "SCORE: %d", player_status.score);
733 text_drawf(&gold_text, str, 0, 224, A_HMIDDLE, A_TOP, 1);
735 sprintf(str, "DISTROS: %d", player_status.distros);
736 text_drawf(&gold_text, str, 0, 256, A_HMIDDLE, A_TOP, 1);
741 wait_for_event(event,2000,5000,true);
745 GameSession::savegame(int)
752 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
754 fi = fopen(savefile, "wb");
758 fprintf(stderr, "Warning: I could not open the slot file ");
762 fputs(level_subset, fi);
764 fwrite(&level,sizeof(int),1,fi);
765 fwrite(&score,sizeof(int),1,fi);
766 fwrite(&distros,sizeof(int),1,fi);
767 fwrite(&scroll_x,sizeof(float),1,fi);
768 //FIXME:fwrite(&tux,sizeof(Player),1,fi);
769 //FIXME:timer_fwrite(&tux.invincible_timer,fi);
770 //FIXME:timer_fwrite(&tux.skidding_timer,fi);
771 //FIXME:timer_fwrite(&tux.safe_timer,fi);
772 //FIXME:timer_fwrite(&tux.frame_timer,fi);
773 timer_fwrite(&time_left,fi);
775 fwrite(&ui,sizeof(int),1,fi);
782 GameSession::loadgame(int)
790 sprintf(savefile,"%s/slot%d.save",st_save_dir,slot);
792 fi = fopen(savefile, "rb");
796 fprintf(stderr, "Warning: I could not open the slot file ");
802 strcpy(level_subset, str);
803 level_subset[strlen(level_subset)-1] = '\0';
804 fread(&level,sizeof(int),1,fi);
806 world->set_defaults();
807 world->get_level()->cleanup();
808 world->arrays_free();
809 world->get_level()->free_gfx();
810 world->get_level()->free_song();
812 if(world->get_level()->load(level_subset,level) != 0)
815 world->activate_bad_guys();
816 world->activate_particle_systems();
817 world->get_level()->load_gfx();
818 world->get_level()->load_song();
821 update_time = st_get_ticks();
823 fread(&score, sizeof(int),1,fi);
824 fread(&distros, sizeof(int),1,fi);
825 fread(&scroll_x,sizeof(float),1,fi);
826 //FIXME:fread(&tux, sizeof(Player), 1, fi);
827 //FIXME:timer_fread(&tux.invincible_timer,fi);
828 //FIXME:timer_fread(&tux.skidding_timer,fi);
829 //FIXME:timer_fread(&tux.safe_timer,fi);
830 //FIXME:timer_fread(&tux.frame_timer,fi);
831 timer_fread(&time_left,fi);
832 fread(&ui,sizeof(int),1,fi);
838 std::string slotinfo(int slot)
845 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
847 fi = fopen(slotfile, "rb");
849 sprintf(tmp,"Slot %d - ",slot);
858 str[strlen(str)-1] = '\0';
860 strcat(tmp, " / Level:");
861 fread(&slot_level,sizeof(int),1,fi);
862 sprintf(str,"%d",slot_level);