6 by Bill Kendrick & Tobias Glaesser
7 bill@newbreedsoftware.com
8 http://www.newbreedsoftware.com/supertux/
10 April 11, 2000 - March 15, 2004
25 #include <sys/types.h>
34 #include "high_scores.h"
42 #include "collision.h"
44 #include "particlesystem.h"
45 #include "resources.h"
47 GameSession* GameSession::current_ = 0;
49 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
50 : world(0), st_gl_mode(mode), levelnb(levelnb_), subset(subset_)
57 GameSession::restart_level()
63 frame_timer.init(true);
65 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
67 world = new World(subset);
69 else if (st_gl_mode == ST_GL_DEMO_GAME)
71 world = new World(subset);
75 world = new World(subset, levelnb);
78 if (st_gl_mode != ST_GL_DEMO_GAME)
80 if(st_gl_mode != ST_GL_TEST)
83 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
91 GameSession::~GameSession()
97 GameSession::levelintro(void)
101 clearscreen(0, 0, 0);
103 sprintf(str, "%s", world->get_level()->name.c_str());
104 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
106 sprintf(str, "TUX x %d", player_status.lives);
107 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
109 sprintf(str, "by %s", world->get_level()->author.c_str());
110 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
116 wait_for_event(event,1000,3000,true);
121 GameSession::start_timers()
123 time_left.start(world->get_level()->time_left*1000);
124 st_pause_ticks_init();
125 update_time = st_get_ticks();
129 GameSession::process_events()
131 Player& tux = *world->get_tux();
134 while (SDL_PollEvent(&event))
136 /* Check for menu-events, if the menu is shown */
137 current_menu->event(event);
141 case SDL_QUIT: /* Quit event - quit: */
142 st_abort("Received window close", "");
145 case SDL_KEYDOWN: /* A keypress! */
147 SDLKey key = event.key.keysym.sym;
149 if(tux.key_event(key,DOWN))
154 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
157 if(st_gl_mode == ST_GL_TEST)
159 exit_status = LEVEL_ABORT;
163 Menu::set_current(game_menu);
165 st_pause_ticks_stop();
169 Menu::set_current(game_menu);
171 st_pause_ticks_start();
180 case SDL_KEYUP: /* A keyrelease! */
182 SDLKey key = event.key.keysym.sym;
184 if(tux.key_event(key, UP))
195 st_pause_ticks_stop();
200 st_pause_ticks_start();
207 tux.size = !tux.size;
210 tux.base.height = 64;
213 tux.base.height = 32;
218 player_status.distros += 50;
226 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
230 --player_status.lives;
234 player_status.score += 1000;
247 case SDL_JOYAXISMOTION:
248 switch(event.jaxis.axis)
251 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
253 tux.input.left = DOWN;
254 tux.input.right = UP;
256 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
259 tux.input.right = DOWN;
263 tux.input.left = DOWN;
264 tux.input.right = DOWN;
268 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
269 tux.input.down = DOWN;
270 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
280 case SDL_JOYBUTTONDOWN:
281 if (event.jbutton.button == JOY_A)
283 else if (event.jbutton.button == JOY_B)
284 tux.input.fire = DOWN;
286 case SDL_JOYBUTTONUP:
287 if (event.jbutton.button == JOY_A)
289 else if (event.jbutton.button == JOY_B)
304 GameSession::check_end_conditions()
306 Player* tux = world->get_tux();
309 if (tux->base.x >= World::current()->get_level()->endpos
310 && World::current()->get_level()->endpos != 0)
312 exit_status = LEVEL_FINISHED;
316 // Check End conditions
320 if (player_status.lives < 0)
322 if(st_gl_mode != ST_GL_TEST)
325 if(st_gl_mode != ST_GL_TEST)
327 if (player_status.score > hs_score)
328 save_hs(player_status.score);
331 exit_status = GAME_OVER;
334 { // Still has lives, so reset Tux to the levelstart
342 GameSession::action(double frame_ratio)
344 check_end_conditions();
346 if (exit_status == NONE)
348 Player* tux = world->get_tux();
350 // Update Tux and the World
351 tux->action(frame_ratio);
352 world->action(frame_ratio);
364 int x = screen->h / 20;
365 for(int i = 0; i < x; ++i)
367 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);
369 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
370 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
375 menu_process_current();
376 mouse_cursor->draw();
383 GameSession::ExitStatus
386 Player* tux = world->get_tux();
391 global_frame_counter = 0;
394 fps_timer.init(true);
395 frame_timer.init(true);
397 last_update_time = st_get_ticks();
401 clearscreen(0, 0, 0);
405 play_current_music();
407 // Eat unneeded events
409 while (SDL_PollEvent(&event)) {}
413 while (exit_status == NONE)
415 /* Calculate the movement-factor */
416 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
417 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
418 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
420 if(!frame_timer.check())
422 frame_timer.start(25);
423 ++global_frame_counter;
427 tux->input.old_fire = tux->input.fire;
433 if(current_menu == game_menu)
435 switch (game_menu->check())
438 st_pause_ticks_stop();
442 //update_load_save_game_menu(save_game_menu);
445 update_load_save_game_menu(load_game_menu);
448 st_pause_ticks_stop();
449 exit_status = LEVEL_ABORT;
453 else if(current_menu == options_menu)
455 process_options_menu();
457 else if(current_menu == load_game_menu )
459 process_load_game_menu();
464 if(!game_pause && !show_menu)
467 if (exit_status != NONE)
476 if(debug_mode && debug_fps)
479 /*Draw the current scene to the screen */
480 /*If the machine running the game is too slow
481 skip the drawing of the frame (so the calculations are more precise and
482 the FPS aren't affected).*/
483 /*if( ! fps_fps < 50.0 )
486 jump = true;*/ /*FIXME: Implement this tweak right.*/
489 /* Time stops in pause mode */
490 if(game_pause || show_menu )
495 /* Set the time of the last update and the time of the current update */
496 last_update_time = update_time;
497 update_time = st_get_ticks();
499 /* Pause till next frame, if the machine running the game is too fast: */
500 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
501 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
502 if(last_update_time >= update_time - 12) {
504 update_time = st_get_ticks();
506 /*if((update_time - last_update_time) < 10)
507 SDL_Delay((11 - (update_time - last_update_time))/2);*/
510 if (time_left.check())
512 /* are we low on time ? */
513 if (time_left.get_left() < TIME_WARNING
514 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
516 set_current_music(HURRYUP_MUSIC);
517 play_current_music();
520 else if(tux->dying == DYING_NOT)
523 /* Calculate frames per second */
527 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
529 if(!fps_timer.check())
531 fps_timer.start(1000);
539 world->get_level()->free_gfx();
540 world->get_level()->cleanup();
541 world->get_level()->free_song();
546 /* Bounce a brick: */
547 void bumpbrick(float x, float y)
549 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
552 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
557 GameSession::drawstatus()
561 sprintf(str, "%d", player_status.score);
562 white_text->draw("SCORE", 0, 0, 1);
563 gold_text->draw(str, 96, 0, 1);
565 if(st_gl_mode != ST_GL_TEST)
567 sprintf(str, "%d", hs_score);
568 white_text->draw("HIGH", 0, 20, 1);
569 gold_text->draw(str, 96, 20, 1);
573 white_text->draw("Press ESC To Return",0,20,1);
576 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
578 sprintf(str, "%d", time_left.get_left() / 1000 );
579 white_text->draw("TIME", 224, 0, 1);
580 gold_text->draw(str, 304, 0, 1);
583 sprintf(str, "%d", player_status.distros);
584 white_text->draw("DISTROS", screen->h, 0, 1);
585 gold_text->draw(str, 608, 0, 1);
587 white_text->draw("LIVES", screen->h, 20, 1);
591 sprintf(str, "%2.1f", fps_fps);
592 white_text->draw("FPS", screen->h, 40, 1);
593 gold_text->draw(str, screen->h + 60, 40, 1);
596 for(int i= 0; i < player_status.lives; ++i)
598 tux_life->draw(565+(18*i),20);
603 GameSession::drawendscreen()
607 clearscreen(0, 0, 0);
609 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
611 sprintf(str, "SCORE: %d", player_status.score);
612 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
614 sprintf(str, "COINS: %d", player_status.distros);
615 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
620 wait_for_event(event,2000,5000,true);
624 GameSession::drawresultscreen(void)
628 clearscreen(0, 0, 0);
630 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
632 sprintf(str, "SCORE: %d", player_status.score);
633 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
635 sprintf(str, "DISTROS: %d", player_status.distros);
636 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
641 wait_for_event(event,2000,5000,true);
644 std::string slotinfo(int slot)
648 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
650 if (access(slotfile, F_OK) == 0)
651 sprintf(tmp,"Slot %d - Savegame",slot);
653 sprintf(tmp,"Slot %d - Free",slot);