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);
122 GameSession::~GameSession()
128 GameSession::levelintro(void)
132 clearscreen(0, 0, 0);
134 sprintf(str, "LEVEL %d", levelnb);
135 blue_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
137 sprintf(str, "%s", world->get_level()->name.c_str());
138 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
140 sprintf(str, "by %s", world->get_level()->author.c_str());
141 red_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
143 sprintf(str, "TUX x %d", player_status.lives);
144 white_text->drawf(str, 0, 288, A_HMIDDLE, A_TOP, 1);
149 wait_for_event(event,1000,3000,true);
154 GameSession::start_timers()
156 time_left.start(world->get_level()->time_left*1000);
157 st_pause_ticks_init();
158 update_time = st_get_ticks();
162 GameSession::process_events()
164 Player& tux = *world->get_tux();
167 while (SDL_PollEvent(&event))
169 /* Check for menu-events, if the menu is shown */
171 current_menu->event(event);
175 case SDL_QUIT: /* Quit event - quit: */
178 case SDL_KEYDOWN: /* A keypress! */
180 SDLKey key = event.key.keysym.sym;
182 if(tux.key_event(key,DOWN))
187 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
190 if(st_gl_mode == ST_GL_TEST)
194 Menu::set_current(game_menu);
196 st_pause_ticks_stop();
200 Menu::set_current(game_menu);
202 st_pause_ticks_start();
211 case SDL_KEYUP: /* A keyrelease! */
213 SDLKey key = event.key.keysym.sym;
215 if(tux.key_event(key, UP))
226 st_pause_ticks_stop();
231 st_pause_ticks_start();
238 tux.size = !tux.size;
241 tux.base.height = 64;
244 tux.base.height = 32;
249 player_status.distros += 50;
253 player_status.next_level = 1;
261 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
265 --player_status.lives;
269 player_status.score += 1000;
282 case SDL_JOYAXISMOTION:
283 switch(event.jaxis.axis)
286 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
288 tux.input.left = DOWN;
289 tux.input.right = UP;
291 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
294 tux.input.right = DOWN;
298 tux.input.left = DOWN;
299 tux.input.right = DOWN;
303 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
304 tux.input.down = DOWN;
305 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
315 case SDL_JOYBUTTONDOWN:
316 if (event.jbutton.button == JOY_A)
318 else if (event.jbutton.button == JOY_B)
319 tux.input.fire = DOWN;
321 case SDL_JOYBUTTONUP:
322 if (event.jbutton.button == JOY_A)
324 else if (event.jbutton.button == JOY_B)
338 GameSession::action(double frame_ratio)
340 Player& tux = *world->get_tux();
342 if (tux.is_dead() || player_status.next_level)
344 /* Tux either died, or reached the end of a level! */
347 if (player_status.next_level)
349 /* End of a level! */
351 player_status.next_level = 0;
352 if(st_gl_mode != ST_GL_TEST)
358 world->get_level()->free_gfx();
359 world->get_level()->cleanup();
360 world->get_level()->free_song();
361 world->arrays_free();
371 /* No more lives!? */
373 if (player_status.lives < 0)
375 if(st_gl_mode != ST_GL_TEST)
378 if(st_gl_mode != ST_GL_TEST)
380 if (player_status.score > hs_score)
381 save_hs(player_status.score);
384 world->get_level()->free_gfx();
385 world->get_level()->cleanup();
386 world->get_level()->free_song();
387 world->arrays_free();
390 } /* if (lives < 0) */
393 /* Either way, (re-)load the (next) level... */
395 world->set_defaults();
397 world->get_level()->cleanup();
399 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
401 if(world->get_level()->load(subset) != 0)
406 if(world->get_level()->load(subset, levelnb) != 0)
410 world->arrays_free();
411 world->activate_bad_guys();
412 world->activate_particle_systems();
414 world->get_level()->free_gfx();
415 world->get_level()->load_gfx();
416 world->get_level()->free_song();
417 world->get_level()->load_song();
419 if(st_gl_mode != ST_GL_TEST)
423 play_current_music();
426 tux.action(frame_ratio);
428 world->action(frame_ratio);
441 int x = screen->h / 20;
442 for(int i = 0; i < x; ++i)
444 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);
446 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
447 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
452 menu_process_current();
453 mouse_cursor->draw();
463 Player& tux = *world->get_tux();
469 global_frame_counter = 0;
472 fps_timer.init(true);
473 frame_timer.init(true);
475 last_update_time = st_get_ticks();
479 clearscreen(0, 0, 0);
483 play_current_music();
485 // Eat unneeded events
487 while (SDL_PollEvent(&event)) {}
493 while (!done && !quit)
495 /* Calculate the movement-factor */
496 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
497 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
498 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
500 if(!frame_timer.check())
502 frame_timer.start(25);
503 ++global_frame_counter;
507 tux.input.old_fire = tux.input.fire;
513 if(current_menu == game_menu)
515 switch (game_menu->check())
518 st_pause_ticks_stop();
521 update_load_save_game_menu(save_game_menu, false);
524 update_load_save_game_menu(load_game_menu, true);
527 st_pause_ticks_stop();
532 else if(current_menu == options_menu)
534 process_options_menu();
536 else if(current_menu == load_game_menu )
538 process_load_game_menu();
543 /* Handle actions: */
545 if(!game_pause && !show_menu)
547 /*float z = frame_ratio;
551 if (action(frame_ratio) == 0)
553 /* == 0: no more lives */
554 /* == -1: continues */
566 if(debug_mode && debug_fps)
569 /*Draw the current scene to the screen */
570 /*If the machine running the game is too slow
571 skip the drawing of the frame (so the calculations are more precise and
572 the FPS aren't affected).*/
573 /*if( ! fps_fps < 50.0 )
576 jump = true;*/ /*FIXME: Implement this tweak right.*/
579 /* Time stops in pause mode */
580 if(game_pause || show_menu )
585 /* Set the time of the last update and the time of the current update */
586 last_update_time = update_time;
587 update_time = st_get_ticks();
589 /* Pause till next frame, if the machine running the game is too fast: */
590 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
591 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
592 if(last_update_time >= update_time - 12) {
594 update_time = st_get_ticks();
596 /*if((update_time - last_update_time) < 10)
597 SDL_Delay((11 - (update_time - last_update_time))/2);*/
600 if (time_left.check())
602 /* are we low on time ? */
603 if (time_left.get_left() < TIME_WARNING
604 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
606 set_current_music(HURRYUP_MUSIC);
607 play_current_music();
611 else if(tux.dying == DYING_NOT)
614 /* Calculate frames per second */
618 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
620 if(!fps_timer.check())
622 fps_timer.start(1000);
630 world->get_level()->free_gfx();
631 world->get_level()->cleanup();
632 world->get_level()->free_song();
634 world->arrays_free();
639 /* Bounce a brick: */
640 void bumpbrick(float x, float y)
642 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
645 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
650 GameSession::drawstatus()
654 sprintf(str, "%d", player_status.score);
655 white_text->draw("SCORE", 0, 0, 1);
656 gold_text->draw(str, 96, 0, 1);
658 if(st_gl_mode != ST_GL_TEST)
660 sprintf(str, "%d", hs_score);
661 white_text->draw("HIGH", 0, 20, 1);
662 gold_text->draw(str, 96, 20, 1);
666 white_text->draw("Press ESC To Return",0,20,1);
669 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
671 sprintf(str, "%d", time_left.get_left() / 1000 );
672 white_text->draw("TIME", 224, 0, 1);
673 gold_text->draw(str, 304, 0, 1);
676 sprintf(str, "%d", player_status.distros);
677 white_text->draw("DISTROS", screen->h, 0, 1);
678 gold_text->draw(str, 608, 0, 1);
680 white_text->draw("LIVES", screen->h, 20, 1);
684 sprintf(str, "%2.1f", fps_fps);
685 white_text->draw("FPS", screen->h, 40, 1);
686 gold_text->draw(str, screen->h + 60, 40, 1);
689 for(int i= 0; i < player_status.lives; ++i)
691 tux_life->draw(565+(18*i),20);
696 GameSession::drawendscreen()
700 clearscreen(0, 0, 0);
702 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
704 sprintf(str, "SCORE: %d", player_status.score);
705 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
707 sprintf(str, "COINS: %d", player_status.distros);
708 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
713 wait_for_event(event,2000,5000,true);
717 GameSession::drawresultscreen(void)
721 clearscreen(0, 0, 0);
723 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
725 sprintf(str, "SCORE: %d", player_status.score);
726 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
728 sprintf(str, "DISTROS: %d", player_status.distros);
729 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
734 wait_for_event(event,2000,5000,true);
737 std::string slotinfo(int slot)
744 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
746 fi = fopen(slotfile, "rb");
748 sprintf(tmp,"Slot %d - ",slot);
757 str[strlen(str)-1] = '\0';
759 strcat(tmp, " / Level:");
760 fread(&slot_level,sizeof(int),1,fi);
761 sprintf(str,"%d",slot_level);