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()->action();
397 Menu::current()->draw();
398 mouse_cursor->draw();
405 GameSession::ExitStatus
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;
454 if(Menu::current() == game_menu)
456 switch (game_menu->check())
459 st_pause_ticks_stop();
462 st_pause_ticks_stop();
463 exit_status = LEVEL_ABORT;
467 else if(Menu::current() == options_menu)
469 process_options_menu();
471 else if(Menu::current() == load_game_menu )
473 process_load_game_menu();
478 if(!game_pause && !Menu::current())
480 frame_ratio *= game_speed;
481 frame_ratio += overlap;
482 while (frame_ratio > 0)
487 overlap = frame_ratio;
489 if (exit_status != NONE)
498 if(debug_mode && debug_fps)
501 /*Draw the current scene to the screen */
502 /*If the machine running the game is too slow
503 skip the drawing of the frame (so the calculations are more precise and
504 the FPS aren't affected).*/
505 /*if( ! fps_fps < 50.0 )
508 jump = true;*/ /*FIXME: Implement this tweak right.*/
511 /* Time stops in pause mode */
512 if(game_pause || Menu::current())
517 /* Set the time of the last update and the time of the current update */
518 last_update_time = update_time;
519 update_time = st_get_ticks();
521 /* Pause till next frame, if the machine running the game is too fast: */
522 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
523 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
524 if(last_update_time >= update_time - 12) {
526 update_time = st_get_ticks();
528 /*if((update_time - last_update_time) < 10)
529 SDL_Delay((11 - (update_time - last_update_time))/2);*/
532 if (time_left.check())
534 /* are we low on time ? */
535 if (time_left.get_left() < TIME_WARNING
536 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
538 set_current_music(HURRYUP_MUSIC);
539 play_current_music();
542 else if(tux->dying == DYING_NOT)
545 /* Calculate frames per second */
549 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
551 if(!fps_timer.check())
553 fps_timer.start(1000);
561 world->get_level()->free_gfx();
562 world->get_level()->cleanup();
563 world->get_level()->free_song();
568 /* Bounce a brick: */
569 void bumpbrick(float x, float y)
571 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
574 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
579 GameSession::drawstatus()
583 sprintf(str, "%d", player_status.score);
584 white_text->draw("SCORE", 0, 0, 1);
585 gold_text->draw(str, 96, 0, 1);
587 if(st_gl_mode == ST_GL_TEST)
589 white_text->draw("Press ESC To Return",0,20,1);
592 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
594 sprintf(str, "%d", time_left.get_left() / 1000 );
595 white_text->draw("TIME", 224, 0, 1);
596 gold_text->draw(str, 304, 0, 1);
599 sprintf(str, "%d", player_status.distros);
600 white_text->draw("DISTROS", screen->h, 0, 1);
601 gold_text->draw(str, 608, 0, 1);
603 white_text->draw("LIVES", screen->h, 20, 1);
607 sprintf(str, "%2.1f", fps_fps);
608 white_text->draw("FPS", screen->h, 40, 1);
609 gold_text->draw(str, screen->h + 60, 40, 1);
612 for(int i= 0; i < player_status.lives; ++i)
614 tux_life->draw(565+(18*i),20);
619 GameSession::drawendscreen()
623 clearscreen(0, 0, 0);
625 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
627 sprintf(str, "SCORE: %d", player_status.score);
628 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
630 sprintf(str, "COINS: %d", player_status.distros);
631 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
636 wait_for_event(event,2000,5000,true);
640 GameSession::drawresultscreen(void)
644 clearscreen(0, 0, 0);
646 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
648 sprintf(str, "SCORE: %d", player_status.score);
649 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
651 sprintf(str, "DISTROS: %d", player_status.distros);
652 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
657 wait_for_event(event,2000,5000,true);
660 std::string slotinfo(int slot)
664 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
666 if (access(slotfile, F_OK) == 0)
667 sprintf(tmp,"Slot %d - Savegame",slot);
669 sprintf(tmp,"Slot %d - Free",slot);