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);
69 { // Tux has lost a life, so we try to respawn him at the nearest reset point
70 old_x_pos = world->get_tux()->base.x;
75 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
77 world = new World(subset);
79 else if (st_gl_mode == ST_GL_DEMO_GAME)
81 world = new World(subset);
85 world = new World(subset, levelnb);
88 // Set Tux to the nearest reset point
91 ResetPoint best_reset_point = { -1, -1 };
92 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
93 i != get_level()->reset_points.end(); ++i)
95 if (i->x < old_x_pos && best_reset_point.x < i->x)
96 best_reset_point = *i;
99 if (best_reset_point.x != -1)
101 world->get_tux()->base.x = best_reset_point.x;
102 world->get_tux()->base.y = best_reset_point.y;
107 if (st_gl_mode != ST_GL_DEMO_GAME)
109 if(st_gl_mode != ST_GL_TEST)
112 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
116 time_left.init(true);
120 GameSession::~GameSession()
126 GameSession::levelintro(void)
130 clearscreen(0, 0, 0);
132 sprintf(str, "%s", world->get_level()->name.c_str());
133 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
135 sprintf(str, "TUX x %d", player_status.lives);
136 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
138 sprintf(str, "by %s", world->get_level()->author.c_str());
139 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
145 wait_for_event(event,1000,3000,true);
150 GameSession::start_timers()
152 time_left.start(world->get_level()->time_left*1000);
153 st_pause_ticks_init();
154 update_time = st_get_ticks();
158 GameSession::on_escape_press()
160 if(st_gl_mode == ST_GL_TEST)
162 exit_status = LEVEL_ABORT;
164 else if (!Menu::current())
166 Menu::set_current(game_menu);
167 st_pause_ticks_stop();
172 GameSession::process_events()
174 Player& tux = *world->get_tux();
177 while (SDL_PollEvent(&event))
179 /* Check for menu-events, if the menu is shown */
182 Menu::current()->event(event);
188 case SDL_QUIT: /* Quit event - quit: */
189 st_abort("Received window close", "");
192 case SDL_KEYDOWN: /* A keypress! */
194 SDLKey key = event.key.keysym.sym;
196 if(tux.key_event(key,DOWN))
201 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
209 case SDL_KEYUP: /* A keyrelease! */
211 SDLKey key = event.key.keysym.sym;
213 if(tux.key_event(key, UP))
224 st_pause_ticks_stop();
229 st_pause_ticks_start();
236 tux.size = !tux.size;
239 tux.base.height = 64;
242 tux.base.height = 32;
247 player_status.distros += 50;
255 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
259 --player_status.lives;
263 player_status.score += 1000;
276 case SDL_JOYAXISMOTION:
277 switch(event.jaxis.axis)
280 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
282 tux.input.left = DOWN;
283 tux.input.right = UP;
285 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
288 tux.input.right = DOWN;
292 tux.input.left = DOWN;
293 tux.input.right = DOWN;
297 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
298 tux.input.down = DOWN;
299 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
309 case SDL_JOYBUTTONDOWN:
310 if (event.jbutton.button == JOY_A)
312 else if (event.jbutton.button == JOY_B)
313 tux.input.fire = DOWN;
314 else if (event.jbutton.button == JOY_START)
317 case SDL_JOYBUTTONUP:
318 if (event.jbutton.button == JOY_A)
320 else if (event.jbutton.button == JOY_B)
333 GameSession::check_end_conditions()
335 Player* tux = world->get_tux();
338 if (tux->base.x >= World::current()->get_level()->endpos
339 && World::current()->get_level()->endpos != 0)
341 exit_status = LEVEL_FINISHED;
345 // Check End conditions
348 player_status.lives -= 1;
350 if (player_status.lives < 0)
352 if(st_gl_mode != ST_GL_TEST)
355 exit_status = GAME_OVER;
358 { // Still has lives, so reset Tux to the levelstart
366 GameSession::action(double frame_ratio)
368 check_end_conditions();
370 if (exit_status == NONE)
372 // Update Tux and the World
373 world->action(frame_ratio);
385 int x = screen->h / 20;
386 for(int i = 0; i < x; ++i)
388 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);
390 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
391 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
396 Menu::current()->draw();
397 mouse_cursor->draw();
404 GameSession::ExitStatus
407 Menu::set_current(0);
408 Player* tux = world->get_tux();
413 global_frame_counter = 0;
416 fps_timer.init(true);
417 frame_timer.init(true);
419 last_update_time = st_get_ticks();
423 clearscreen(0, 0, 0);
427 play_current_music();
429 // Eat unneeded events
431 while (SDL_PollEvent(&event)) {}
435 float overlap = 0.0f;
436 while (exit_status == NONE)
438 /* Calculate the movement-factor */
439 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
441 if(!frame_timer.check())
443 frame_timer.start(25);
444 ++global_frame_counter;
448 tux->input.old_fire = tux->input.fire;
452 Menu* menu = Menu::current();
457 if(menu == game_menu)
459 switch (game_menu->check())
462 st_pause_ticks_stop();
465 st_pause_ticks_stop();
466 exit_status = LEVEL_ABORT;
470 else if(menu == options_menu)
472 process_options_menu();
474 else if(menu == load_game_menu )
476 process_load_game_menu();
481 if(!game_pause && !Menu::current())
483 frame_ratio *= game_speed;
484 frame_ratio += overlap;
485 while (frame_ratio > 0)
490 overlap = frame_ratio;
492 if (exit_status != NONE)
501 if(debug_mode && debug_fps)
504 /*Draw the current scene to the screen */
505 /*If the machine running the game is too slow
506 skip the drawing of the frame (so the calculations are more precise and
507 the FPS aren't affected).*/
508 /*if( ! fps_fps < 50.0 )
511 jump = true;*/ /*FIXME: Implement this tweak right.*/
514 /* Time stops in pause mode */
515 if(game_pause || Menu::current())
520 /* Set the time of the last update and the time of the current update */
521 last_update_time = update_time;
522 update_time = st_get_ticks();
524 /* Pause till next frame, if the machine running the game is too fast: */
525 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
526 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
527 if(last_update_time >= update_time - 12) {
529 update_time = st_get_ticks();
531 /*if((update_time - last_update_time) < 10)
532 SDL_Delay((11 - (update_time - last_update_time))/2);*/
535 if (time_left.check())
537 /* are we low on time ? */
538 if (time_left.get_left() < TIME_WARNING
539 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
541 set_current_music(HURRYUP_MUSIC);
542 play_current_music();
545 else if(tux->dying == DYING_NOT)
548 /* Calculate frames per second */
552 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
554 if(!fps_timer.check())
556 fps_timer.start(1000);
564 world->get_level()->free_gfx();
565 world->get_level()->cleanup();
566 world->get_level()->free_song();
571 /* Bounce a brick: */
572 void bumpbrick(float x, float y)
574 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
577 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
582 GameSession::drawstatus()
586 sprintf(str, "%d", player_status.score);
587 white_text->draw("SCORE", 0, 0, 1);
588 gold_text->draw(str, 96, 0, 1);
590 if(st_gl_mode == ST_GL_TEST)
592 white_text->draw("Press ESC To Return",0,20,1);
595 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
597 sprintf(str, "%d", time_left.get_left() / 1000 );
598 white_text->draw("TIME", 224, 0, 1);
599 gold_text->draw(str, 304, 0, 1);
602 sprintf(str, "%d", player_status.distros);
603 white_text->draw("DISTROS", screen->h, 0, 1);
604 gold_text->draw(str, 608, 0, 1);
606 white_text->draw("LIVES", screen->h, 20, 1);
610 sprintf(str, "%2.1f", fps_fps);
611 white_text->draw("FPS", screen->h, 40, 1);
612 gold_text->draw(str, screen->h + 60, 40, 1);
615 for(int i= 0; i < player_status.lives; ++i)
617 tux_life->draw(565+(18*i),20);
622 GameSession::drawendscreen()
626 clearscreen(0, 0, 0);
628 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
630 sprintf(str, "SCORE: %d", player_status.score);
631 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
633 sprintf(str, "COINS: %d", player_status.distros);
634 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
639 wait_for_event(event,2000,5000,true);
643 GameSession::drawresultscreen(void)
647 clearscreen(0, 0, 0);
649 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
651 sprintf(str, "SCORE: %d", player_status.score);
652 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
654 sprintf(str, "DISTROS: %d", player_status.distros);
655 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
660 wait_for_event(event,2000,5000,true);
663 std::string slotinfo(int slot)
667 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
669 if (access(slotfile, F_OK) == 0)
670 sprintf(tmp,"Slot %d - Savegame",slot);
672 sprintf(tmp,"Slot %d - Free",slot);