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()
134 if(st_gl_mode == ST_GL_TEST)
136 exit_status = LEVEL_ABORT;
138 else if (!Menu::current())
140 Menu::set_current(game_menu);
141 st_pause_ticks_stop();
146 GameSession::process_events()
148 Player& tux = *world->get_tux();
151 while (SDL_PollEvent(&event))
153 /* Check for menu-events, if the menu is shown */
156 Menu::current()->event(event);
162 case SDL_QUIT: /* Quit event - quit: */
163 st_abort("Received window close", "");
166 case SDL_KEYDOWN: /* A keypress! */
168 SDLKey key = event.key.keysym.sym;
170 if(tux.key_event(key,DOWN))
175 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
183 case SDL_KEYUP: /* A keyrelease! */
185 SDLKey key = event.key.keysym.sym;
187 if(tux.key_event(key, UP))
198 st_pause_ticks_stop();
203 st_pause_ticks_start();
210 tux.size = !tux.size;
213 tux.base.height = 64;
216 tux.base.height = 32;
221 player_status.distros += 50;
229 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
233 --player_status.lives;
237 player_status.score += 1000;
250 case SDL_JOYAXISMOTION:
251 switch(event.jaxis.axis)
254 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
256 tux.input.left = DOWN;
257 tux.input.right = UP;
259 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
262 tux.input.right = DOWN;
266 tux.input.left = DOWN;
267 tux.input.right = DOWN;
271 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
272 tux.input.down = DOWN;
273 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
283 case SDL_JOYBUTTONDOWN:
284 if (event.jbutton.button == JOY_A)
286 else if (event.jbutton.button == JOY_B)
287 tux.input.fire = DOWN;
288 else if (event.jbutton.button == JOY_START)
291 case SDL_JOYBUTTONUP:
292 if (event.jbutton.button == JOY_A)
294 else if (event.jbutton.button == JOY_B)
307 GameSession::check_end_conditions()
309 Player* tux = world->get_tux();
312 if (tux->base.x >= World::current()->get_level()->endpos
313 && World::current()->get_level()->endpos != 0)
315 exit_status = LEVEL_FINISHED;
319 // Check End conditions
322 player_status.lives -= 1;
324 if (player_status.lives < 0)
326 if(st_gl_mode != ST_GL_TEST)
329 exit_status = GAME_OVER;
332 { // Still has lives, so reset Tux to the levelstart
340 GameSession::action(double frame_ratio)
342 check_end_conditions();
344 if (exit_status == NONE)
346 // Update Tux and the World
347 world->action(frame_ratio);
359 int x = screen->h / 20;
360 for(int i = 0; i < x; ++i)
362 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);
364 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
365 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
370 Menu::current()->action();
371 Menu::current()->draw();
372 mouse_cursor->draw();
379 GameSession::ExitStatus
382 Player* tux = world->get_tux();
387 global_frame_counter = 0;
390 fps_timer.init(true);
391 frame_timer.init(true);
393 last_update_time = st_get_ticks();
397 clearscreen(0, 0, 0);
401 play_current_music();
403 // Eat unneeded events
405 while (SDL_PollEvent(&event)) {}
409 float overlap = 0.0f;
410 while (exit_status == NONE)
412 /* Calculate the movement-factor */
413 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
415 if(!frame_timer.check())
417 frame_timer.start(25);
418 ++global_frame_counter;
422 tux->input.old_fire = tux->input.fire;
428 if(Menu::current() == game_menu)
430 switch (game_menu->check())
433 st_pause_ticks_stop();
436 st_pause_ticks_stop();
437 exit_status = LEVEL_ABORT;
441 else if(Menu::current() == options_menu)
443 process_options_menu();
445 else if(Menu::current() == load_game_menu )
447 process_load_game_menu();
452 if(!game_pause && !Menu::current())
454 frame_ratio *= game_speed;
455 frame_ratio += overlap;
456 while (frame_ratio > 0)
461 overlap = frame_ratio;
463 if (exit_status != NONE)
472 if(debug_mode && debug_fps)
475 /*Draw the current scene to the screen */
476 /*If the machine running the game is too slow
477 skip the drawing of the frame (so the calculations are more precise and
478 the FPS aren't affected).*/
479 /*if( ! fps_fps < 50.0 )
482 jump = true;*/ /*FIXME: Implement this tweak right.*/
485 /* Time stops in pause mode */
486 if(game_pause || Menu::current())
491 /* Set the time of the last update and the time of the current update */
492 last_update_time = update_time;
493 update_time = st_get_ticks();
495 /* Pause till next frame, if the machine running the game is too fast: */
496 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
497 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
498 if(last_update_time >= update_time - 12) {
500 update_time = st_get_ticks();
502 /*if((update_time - last_update_time) < 10)
503 SDL_Delay((11 - (update_time - last_update_time))/2);*/
506 if (time_left.check())
508 /* are we low on time ? */
509 if (time_left.get_left() < TIME_WARNING
510 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
512 set_current_music(HURRYUP_MUSIC);
513 play_current_music();
516 else if(tux->dying == DYING_NOT)
519 /* Calculate frames per second */
523 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
525 if(!fps_timer.check())
527 fps_timer.start(1000);
535 world->get_level()->free_gfx();
536 world->get_level()->cleanup();
537 world->get_level()->free_song();
542 /* Bounce a brick: */
543 void bumpbrick(float x, float y)
545 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
548 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
553 GameSession::drawstatus()
557 sprintf(str, "%d", player_status.score);
558 white_text->draw("SCORE", 0, 0, 1);
559 gold_text->draw(str, 96, 0, 1);
561 if(st_gl_mode == ST_GL_TEST)
563 white_text->draw("Press ESC To Return",0,20,1);
566 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
568 sprintf(str, "%d", time_left.get_left() / 1000 );
569 white_text->draw("TIME", 224, 0, 1);
570 gold_text->draw(str, 304, 0, 1);
573 sprintf(str, "%d", player_status.distros);
574 white_text->draw("DISTROS", screen->h, 0, 1);
575 gold_text->draw(str, 608, 0, 1);
577 white_text->draw("LIVES", screen->h, 20, 1);
581 sprintf(str, "%2.1f", fps_fps);
582 white_text->draw("FPS", screen->h, 40, 1);
583 gold_text->draw(str, screen->h + 60, 40, 1);
586 for(int i= 0; i < player_status.lives; ++i)
588 tux_life->draw(565+(18*i),20);
593 GameSession::drawendscreen()
597 clearscreen(0, 0, 0);
599 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
601 sprintf(str, "SCORE: %d", player_status.score);
602 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
604 sprintf(str, "COINS: %d", player_status.distros);
605 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
610 wait_for_event(event,2000,5000,true);
614 GameSession::drawresultscreen(void)
618 clearscreen(0, 0, 0);
620 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
622 sprintf(str, "SCORE: %d", player_status.score);
623 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
625 sprintf(str, "DISTROS: %d", player_status.distros);
626 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
631 wait_for_event(event,2000,5000,true);
634 std::string slotinfo(int slot)
638 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
640 if (access(slotfile, F_OK) == 0)
641 sprintf(tmp,"Slot %d - Savegame",slot);
643 sprintf(tmp,"Slot %d - Free",slot);