6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
26 #include <sys/types.h>
35 #include "high_scores.h"
43 #include "collision.h"
45 #include "particlesystem.h"
46 #include "resources.h"
48 GameSession* GameSession::current_ = 0;
50 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
51 : world(0), st_gl_mode(mode), levelnb(levelnb_), subset(subset_)
58 GameSession::restart_level()
64 frame_timer.init(true);
68 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
70 world = new World(subset);
72 else if (st_gl_mode == ST_GL_DEMO_GAME)
74 world = new World(subset);
78 world = new World(subset, levelnb);
81 if (st_gl_mode != ST_GL_DEMO_GAME)
83 if(st_gl_mode != ST_GL_TEST)
86 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
94 GameSession::~GameSession()
100 GameSession::levelintro(void)
104 clearscreen(0, 0, 0);
106 sprintf(str, "%s", world->get_level()->name.c_str());
107 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
109 sprintf(str, "TUX x %d", player_status.lives);
110 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
112 sprintf(str, "by %s", world->get_level()->author.c_str());
113 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
119 wait_for_event(event,1000,3000,true);
124 GameSession::start_timers()
126 time_left.start(world->get_level()->time_left*1000);
127 st_pause_ticks_init();
128 update_time = st_get_ticks();
132 GameSession::on_escape_press()
136 if(st_gl_mode == ST_GL_TEST)
138 exit_status = LEVEL_ABORT;
140 else if (!Menu::current())
142 Menu::set_current(game_menu);
143 st_pause_ticks_stop();
147 Menu::set_current(NULL);
148 st_pause_ticks_start();
154 GameSession::process_events()
156 Player& tux = *world->get_tux();
159 while (SDL_PollEvent(&event))
161 /* Check for menu-events, if the menu is shown */
163 Menu::current()->event(event);
167 case SDL_QUIT: /* Quit event - quit: */
168 st_abort("Received window close", "");
171 case SDL_KEYDOWN: /* A keypress! */
173 SDLKey key = event.key.keysym.sym;
175 if(tux.key_event(key,DOWN))
180 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
188 case SDL_KEYUP: /* A keyrelease! */
190 SDLKey key = event.key.keysym.sym;
192 if(tux.key_event(key, UP))
203 st_pause_ticks_stop();
208 st_pause_ticks_start();
215 tux.size = !tux.size;
218 tux.base.height = 64;
221 tux.base.height = 32;
226 player_status.distros += 50;
234 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
238 --player_status.lives;
242 player_status.score += 1000;
255 case SDL_JOYAXISMOTION:
256 switch(event.jaxis.axis)
259 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
261 tux.input.left = DOWN;
262 tux.input.right = UP;
264 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
267 tux.input.right = DOWN;
271 tux.input.left = DOWN;
272 tux.input.right = DOWN;
276 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
277 tux.input.down = DOWN;
278 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
288 case SDL_JOYBUTTONDOWN:
289 if (event.jbutton.button == JOY_A)
291 else if (event.jbutton.button == JOY_B)
292 tux.input.fire = DOWN;
293 else if (event.jbutton.button == JOY_START)
296 case SDL_JOYBUTTONUP:
297 if (event.jbutton.button == JOY_A)
299 else if (event.jbutton.button == JOY_B)
313 GameSession::check_end_conditions()
315 Player* tux = world->get_tux();
318 if (tux->base.x >= World::current()->get_level()->endpos
319 && World::current()->get_level()->endpos != 0)
321 exit_status = LEVEL_FINISHED;
325 // Check End conditions
328 player_status.lives -= 1;
330 if (player_status.lives < 0)
332 if(st_gl_mode != ST_GL_TEST)
335 if(st_gl_mode != ST_GL_TEST)
337 // FIXME: highscore soving doesn't make sense in its
339 //if (player_status.score > hs_score)
340 //save_hs(player_status.score);
343 exit_status = GAME_OVER;
346 { // Still has lives, so reset Tux to the levelstart
354 GameSession::action(double frame_ratio)
356 check_end_conditions();
358 if (exit_status == NONE)
360 // Update Tux and the World
361 world->action(frame_ratio);
373 int x = screen->h / 20;
374 for(int i = 0; i < x; ++i)
376 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);
378 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
379 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
384 Menu::current()->action();
385 Menu::current()->draw();
386 mouse_cursor->draw();
393 GameSession::ExitStatus
396 Player* tux = world->get_tux();
401 global_frame_counter = 0;
404 fps_timer.init(true);
405 frame_timer.init(true);
407 last_update_time = st_get_ticks();
411 clearscreen(0, 0, 0);
415 play_current_music();
417 // Eat unneeded events
419 while (SDL_PollEvent(&event)) {}
423 float overlap = 0.0f;
424 while (exit_status == NONE)
426 /* Calculate the movement-factor */
427 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
429 if(!frame_timer.check())
431 frame_timer.start(25);
432 ++global_frame_counter;
436 tux->input.old_fire = tux->input.fire;
442 if(Menu::current() == game_menu)
444 switch (game_menu->check())
447 st_pause_ticks_stop();
450 st_pause_ticks_stop();
451 exit_status = LEVEL_ABORT;
455 else if(Menu::current() == options_menu)
457 process_options_menu();
459 else if(Menu::current() == load_game_menu )
461 process_load_game_menu();
466 if(!game_pause && !Menu::current())
468 frame_ratio *= game_speed;
469 frame_ratio += overlap;
470 while (frame_ratio > 0)
475 overlap = frame_ratio;
477 if (exit_status != NONE)
486 if(debug_mode && debug_fps)
489 /*Draw the current scene to the screen */
490 /*If the machine running the game is too slow
491 skip the drawing of the frame (so the calculations are more precise and
492 the FPS aren't affected).*/
493 /*if( ! fps_fps < 50.0 )
496 jump = true;*/ /*FIXME: Implement this tweak right.*/
499 /* Time stops in pause mode */
500 if(game_pause || Menu::current())
505 /* Set the time of the last update and the time of the current update */
506 last_update_time = update_time;
507 update_time = st_get_ticks();
509 /* Pause till next frame, if the machine running the game is too fast: */
510 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
511 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
512 if(last_update_time >= update_time - 12) {
514 update_time = st_get_ticks();
516 /*if((update_time - last_update_time) < 10)
517 SDL_Delay((11 - (update_time - last_update_time))/2);*/
520 if (time_left.check())
522 /* are we low on time ? */
523 if (time_left.get_left() < TIME_WARNING
524 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
526 set_current_music(HURRYUP_MUSIC);
527 play_current_music();
530 else if(tux->dying == DYING_NOT)
533 /* Calculate frames per second */
537 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
539 if(!fps_timer.check())
541 fps_timer.start(1000);
549 world->get_level()->free_gfx();
550 world->get_level()->cleanup();
551 world->get_level()->free_song();
556 /* Bounce a brick: */
557 void bumpbrick(float x, float y)
559 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
562 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
567 GameSession::drawstatus()
571 sprintf(str, "%d", player_status.score);
572 white_text->draw("SCORE", 0, 0, 1);
573 gold_text->draw(str, 96, 0, 1);
575 if(st_gl_mode != ST_GL_TEST)
577 sprintf(str, "%d", hs_score);
578 white_text->draw("HIGH", 0, 20, 1);
579 gold_text->draw(str, 96, 20, 1);
583 white_text->draw("Press ESC To Return",0,20,1);
586 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
588 sprintf(str, "%d", time_left.get_left() / 1000 );
589 white_text->draw("TIME", 224, 0, 1);
590 gold_text->draw(str, 304, 0, 1);
593 sprintf(str, "%d", player_status.distros);
594 white_text->draw("DISTROS", screen->h, 0, 1);
595 gold_text->draw(str, 608, 0, 1);
597 white_text->draw("LIVES", screen->h, 20, 1);
601 sprintf(str, "%2.1f", fps_fps);
602 white_text->draw("FPS", screen->h, 40, 1);
603 gold_text->draw(str, screen->h + 60, 40, 1);
606 for(int i= 0; i < player_status.lives; ++i)
608 tux_life->draw(565+(18*i),20);
613 GameSession::drawendscreen()
617 clearscreen(0, 0, 0);
619 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
621 sprintf(str, "SCORE: %d", player_status.score);
622 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
624 sprintf(str, "COINS: %d", player_status.distros);
625 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
630 wait_for_event(event,2000,5000,true);
634 GameSession::drawresultscreen(void)
638 clearscreen(0, 0, 0);
640 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
642 sprintf(str, "SCORE: %d", player_status.score);
643 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
645 sprintf(str, "DISTROS: %d", player_status.distros);
646 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
651 wait_for_event(event,2000,5000,true);
654 std::string slotinfo(int slot)
658 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
660 if (access(slotfile, F_OK) == 0)
661 sprintf(tmp,"Slot %d - Savegame",slot);
663 sprintf(tmp,"Slot %d - Free",slot);