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);
66 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
68 world = new World(subset);
70 else if (st_gl_mode == ST_GL_DEMO_GAME)
72 world = new World(subset);
76 world = new World(subset, levelnb);
79 if (st_gl_mode != ST_GL_DEMO_GAME)
81 if(st_gl_mode != ST_GL_TEST)
84 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
92 GameSession::~GameSession()
98 GameSession::levelintro(void)
102 clearscreen(0, 0, 0);
104 sprintf(str, "%s", world->get_level()->name.c_str());
105 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
107 sprintf(str, "TUX x %d", player_status.lives);
108 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
110 sprintf(str, "by %s", world->get_level()->author.c_str());
111 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
117 wait_for_event(event,1000,3000,true);
122 GameSession::start_timers()
124 time_left.start(world->get_level()->time_left*1000);
125 st_pause_ticks_init();
126 update_time = st_get_ticks();
130 GameSession::process_events()
132 Player& tux = *world->get_tux();
135 while (SDL_PollEvent(&event))
137 /* Check for menu-events, if the menu is shown */
138 current_menu->event(event);
142 case SDL_QUIT: /* Quit event - quit: */
143 st_abort("Received window close", "");
146 case SDL_KEYDOWN: /* A keypress! */
148 SDLKey key = event.key.keysym.sym;
150 if(tux.key_event(key,DOWN))
155 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
158 if(st_gl_mode == ST_GL_TEST)
160 exit_status = LEVEL_ABORT;
164 Menu::set_current(game_menu);
166 st_pause_ticks_stop();
170 Menu::set_current(game_menu);
172 st_pause_ticks_start();
181 case SDL_KEYUP: /* A keyrelease! */
183 SDLKey key = event.key.keysym.sym;
185 if(tux.key_event(key, UP))
196 st_pause_ticks_stop();
201 st_pause_ticks_start();
208 tux.size = !tux.size;
211 tux.base.height = 64;
214 tux.base.height = 32;
219 player_status.distros += 50;
227 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
231 --player_status.lives;
235 player_status.score += 1000;
248 case SDL_JOYAXISMOTION:
249 switch(event.jaxis.axis)
252 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
254 tux.input.left = DOWN;
255 tux.input.right = UP;
257 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
260 tux.input.right = DOWN;
264 tux.input.left = DOWN;
265 tux.input.right = DOWN;
269 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
270 tux.input.down = DOWN;
271 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
281 case SDL_JOYBUTTONDOWN:
282 if (event.jbutton.button == JOY_A)
284 else if (event.jbutton.button == JOY_B)
285 tux.input.fire = DOWN;
287 case SDL_JOYBUTTONUP:
288 if (event.jbutton.button == JOY_A)
290 else if (event.jbutton.button == JOY_B)
305 GameSession::check_end_conditions()
307 Player* tux = world->get_tux();
310 if (tux->base.x >= World::current()->get_level()->endpos
311 && World::current()->get_level()->endpos != 0)
313 exit_status = LEVEL_FINISHED;
317 // Check End conditions
321 if (player_status.lives < 0)
323 if(st_gl_mode != ST_GL_TEST)
326 if(st_gl_mode != ST_GL_TEST)
328 if (player_status.score > hs_score)
329 save_hs(player_status.score);
332 exit_status = GAME_OVER;
335 { // Still has lives, so reset Tux to the levelstart
343 GameSession::action(double frame_ratio)
345 check_end_conditions();
347 if (exit_status == NONE)
349 // Update Tux and the World
350 world->action(frame_ratio);
362 int x = screen->h / 20;
363 for(int i = 0; i < x; ++i)
365 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);
367 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
368 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
373 menu_process_current();
374 mouse_cursor->draw();
381 GameSession::ExitStatus
384 Player* tux = world->get_tux();
389 global_frame_counter = 0;
392 fps_timer.init(true);
393 frame_timer.init(true);
395 last_update_time = st_get_ticks();
399 clearscreen(0, 0, 0);
403 play_current_music();
405 // Eat unneeded events
407 while (SDL_PollEvent(&event)) {}
411 float overlap = 0.0f;
412 while (exit_status == NONE)
414 /* Calculate the movement-factor */
415 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
417 if(!frame_timer.check())
419 frame_timer.start(25);
420 ++global_frame_counter;
424 tux->input.old_fire = tux->input.fire;
430 if(current_menu == game_menu)
432 switch (game_menu->check())
435 st_pause_ticks_stop();
439 //update_load_save_game_menu(save_game_menu);
442 update_load_save_game_menu(load_game_menu);
445 st_pause_ticks_stop();
446 exit_status = LEVEL_ABORT;
450 else if(current_menu == options_menu)
452 process_options_menu();
454 else if(current_menu == load_game_menu )
456 process_load_game_menu();
461 if(!game_pause && !show_menu)
463 frame_ratio *= game_speed;
464 frame_ratio += overlap;
465 while (frame_ratio > 0)
470 overlap = frame_ratio;
472 if (exit_status != NONE)
481 if(debug_mode && debug_fps)
484 /*Draw the current scene to the screen */
485 /*If the machine running the game is too slow
486 skip the drawing of the frame (so the calculations are more precise and
487 the FPS aren't affected).*/
488 /*if( ! fps_fps < 50.0 )
491 jump = true;*/ /*FIXME: Implement this tweak right.*/
494 /* Time stops in pause mode */
495 if(game_pause || show_menu )
500 /* Set the time of the last update and the time of the current update */
501 last_update_time = update_time;
502 update_time = st_get_ticks();
504 /* Pause till next frame, if the machine running the game is too fast: */
505 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
506 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
507 if(last_update_time >= update_time - 12) {
509 update_time = st_get_ticks();
511 /*if((update_time - last_update_time) < 10)
512 SDL_Delay((11 - (update_time - last_update_time))/2);*/
515 if (time_left.check())
517 /* are we low on time ? */
518 if (time_left.get_left() < TIME_WARNING
519 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
521 set_current_music(HURRYUP_MUSIC);
522 play_current_music();
525 else if(tux->dying == DYING_NOT)
528 /* Calculate frames per second */
532 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
534 if(!fps_timer.check())
536 fps_timer.start(1000);
544 world->get_level()->free_gfx();
545 world->get_level()->cleanup();
546 world->get_level()->free_song();
551 /* Bounce a brick: */
552 void bumpbrick(float x, float y)
554 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
557 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
562 GameSession::drawstatus()
566 sprintf(str, "%d", player_status.score);
567 white_text->draw("SCORE", 0, 0, 1);
568 gold_text->draw(str, 96, 0, 1);
570 if(st_gl_mode != ST_GL_TEST)
572 sprintf(str, "%d", hs_score);
573 white_text->draw("HIGH", 0, 20, 1);
574 gold_text->draw(str, 96, 20, 1);
578 white_text->draw("Press ESC To Return",0,20,1);
581 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
583 sprintf(str, "%d", time_left.get_left() / 1000 );
584 white_text->draw("TIME", 224, 0, 1);
585 gold_text->draw(str, 304, 0, 1);
588 sprintf(str, "%d", player_status.distros);
589 white_text->draw("DISTROS", screen->h, 0, 1);
590 gold_text->draw(str, 608, 0, 1);
592 white_text->draw("LIVES", screen->h, 20, 1);
596 sprintf(str, "%2.1f", fps_fps);
597 white_text->draw("FPS", screen->h, 40, 1);
598 gold_text->draw(str, screen->h + 60, 40, 1);
601 for(int i= 0; i < player_status.lives; ++i)
603 tux_life->draw(565+(18*i),20);
608 GameSession::drawendscreen()
612 clearscreen(0, 0, 0);
614 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
616 sprintf(str, "SCORE: %d", player_status.score);
617 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
619 sprintf(str, "COINS: %d", player_status.distros);
620 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
625 wait_for_event(event,2000,5000,true);
629 GameSession::drawresultscreen(void)
633 clearscreen(0, 0, 0);
635 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
637 sprintf(str, "SCORE: %d", player_status.score);
638 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
640 sprintf(str, "DISTROS: %d", player_status.distros);
641 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
646 wait_for_event(event,2000,5000,true);
649 std::string slotinfo(int slot)
653 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
655 if (access(slotfile, F_OK) == 0)
656 sprintf(tmp,"Slot %d - Savegame",slot);
658 sprintf(tmp,"Slot %d - Free",slot);