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_process_current();
385 mouse_cursor->draw();
392 GameSession::ExitStatus
395 Player* tux = world->get_tux();
400 global_frame_counter = 0;
403 fps_timer.init(true);
404 frame_timer.init(true);
406 last_update_time = st_get_ticks();
410 clearscreen(0, 0, 0);
414 play_current_music();
416 // Eat unneeded events
418 while (SDL_PollEvent(&event)) {}
422 float overlap = 0.0f;
423 while (exit_status == NONE)
425 /* Calculate the movement-factor */
426 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
428 if(!frame_timer.check())
430 frame_timer.start(25);
431 ++global_frame_counter;
435 tux->input.old_fire = tux->input.fire;
441 if(Menu::current() == game_menu)
443 switch (game_menu->check())
446 st_pause_ticks_stop();
449 st_pause_ticks_stop();
450 exit_status = LEVEL_ABORT;
454 else if(Menu::current() == options_menu)
456 process_options_menu();
458 else if(Menu::current() == load_game_menu )
460 process_load_game_menu();
465 if(!game_pause && !Menu::current())
467 frame_ratio *= game_speed;
468 frame_ratio += overlap;
469 while (frame_ratio > 0)
474 overlap = frame_ratio;
476 if (exit_status != NONE)
485 if(debug_mode && debug_fps)
488 /*Draw the current scene to the screen */
489 /*If the machine running the game is too slow
490 skip the drawing of the frame (so the calculations are more precise and
491 the FPS aren't affected).*/
492 /*if( ! fps_fps < 50.0 )
495 jump = true;*/ /*FIXME: Implement this tweak right.*/
498 /* Time stops in pause mode */
499 if(game_pause || Menu::current())
504 /* Set the time of the last update and the time of the current update */
505 last_update_time = update_time;
506 update_time = st_get_ticks();
508 /* Pause till next frame, if the machine running the game is too fast: */
509 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
510 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
511 if(last_update_time >= update_time - 12) {
513 update_time = st_get_ticks();
515 /*if((update_time - last_update_time) < 10)
516 SDL_Delay((11 - (update_time - last_update_time))/2);*/
519 if (time_left.check())
521 /* are we low on time ? */
522 if (time_left.get_left() < TIME_WARNING
523 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
525 set_current_music(HURRYUP_MUSIC);
526 play_current_music();
529 else if(tux->dying == DYING_NOT)
532 /* Calculate frames per second */
536 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
538 if(!fps_timer.check())
540 fps_timer.start(1000);
548 world->get_level()->free_gfx();
549 world->get_level()->cleanup();
550 world->get_level()->free_song();
555 /* Bounce a brick: */
556 void bumpbrick(float x, float y)
558 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
561 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
566 GameSession::drawstatus()
570 sprintf(str, "%d", player_status.score);
571 white_text->draw("SCORE", 0, 0, 1);
572 gold_text->draw(str, 96, 0, 1);
574 if(st_gl_mode != ST_GL_TEST)
576 sprintf(str, "%d", hs_score);
577 white_text->draw("HIGH", 0, 20, 1);
578 gold_text->draw(str, 96, 20, 1);
582 white_text->draw("Press ESC To Return",0,20,1);
585 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
587 sprintf(str, "%d", time_left.get_left() / 1000 );
588 white_text->draw("TIME", 224, 0, 1);
589 gold_text->draw(str, 304, 0, 1);
592 sprintf(str, "%d", player_status.distros);
593 white_text->draw("DISTROS", screen->h, 0, 1);
594 gold_text->draw(str, 608, 0, 1);
596 white_text->draw("LIVES", screen->h, 20, 1);
600 sprintf(str, "%2.1f", fps_fps);
601 white_text->draw("FPS", screen->h, 40, 1);
602 gold_text->draw(str, screen->h + 60, 40, 1);
605 for(int i= 0; i < player_status.lives; ++i)
607 tux_life->draw(565+(18*i),20);
612 GameSession::drawendscreen()
616 clearscreen(0, 0, 0);
618 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
620 sprintf(str, "SCORE: %d", player_status.score);
621 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
623 sprintf(str, "COINS: %d", player_status.distros);
624 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
629 wait_for_event(event,2000,5000,true);
633 GameSession::drawresultscreen(void)
637 clearscreen(0, 0, 0);
639 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
641 sprintf(str, "SCORE: %d", player_status.score);
642 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
644 sprintf(str, "DISTROS: %d", player_status.distros);
645 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
650 wait_for_event(event,2000,5000,true);
653 std::string slotinfo(int slot)
657 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
659 if (access(slotfile, F_OK) == 0)
660 sprintf(tmp,"Slot %d - Savegame",slot);
662 sprintf(tmp,"Slot %d - Free",slot);