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::process_events()
134 Player& tux = *world->get_tux();
137 while (SDL_PollEvent(&event))
139 /* Check for menu-events, if the menu is shown */
140 current_menu->event(event);
144 case SDL_QUIT: /* Quit event - quit: */
145 st_abort("Received window close", "");
148 case SDL_KEYDOWN: /* A keypress! */
150 SDLKey key = event.key.keysym.sym;
152 if(tux.key_event(key,DOWN))
157 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
160 if(st_gl_mode == ST_GL_TEST)
162 exit_status = LEVEL_ABORT;
166 Menu::set_current(game_menu);
168 st_pause_ticks_stop();
172 Menu::set_current(game_menu);
174 st_pause_ticks_start();
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;
289 case SDL_JOYBUTTONUP:
290 if (event.jbutton.button == JOY_A)
292 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
323 if (player_status.lives < 0)
325 if(st_gl_mode != ST_GL_TEST)
328 if(st_gl_mode != ST_GL_TEST)
330 if (player_status.score > hs_score)
331 save_hs(player_status.score);
334 exit_status = GAME_OVER;
337 { // Still has lives, so reset Tux to the levelstart
345 GameSession::action(double frame_ratio)
347 check_end_conditions();
349 if (exit_status == NONE)
351 // Update Tux and the World
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 float overlap = 0.0f;
414 while (exit_status == NONE)
416 /* Calculate the movement-factor */
417 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
419 if(!frame_timer.check())
421 frame_timer.start(25);
422 ++global_frame_counter;
426 tux->input.old_fire = tux->input.fire;
432 if(current_menu == game_menu)
434 switch (game_menu->check())
437 st_pause_ticks_stop();
441 //update_load_save_game_menu(save_game_menu);
444 update_load_save_game_menu(load_game_menu);
447 st_pause_ticks_stop();
448 exit_status = LEVEL_ABORT;
452 else if(current_menu == options_menu)
454 process_options_menu();
456 else if(current_menu == load_game_menu )
458 process_load_game_menu();
463 if(!game_pause && !show_menu)
465 frame_ratio *= game_speed;
466 frame_ratio += overlap;
467 while (frame_ratio > 0)
472 overlap = frame_ratio;
474 if (exit_status != NONE)
483 if(debug_mode && debug_fps)
486 /*Draw the current scene to the screen */
487 /*If the machine running the game is too slow
488 skip the drawing of the frame (so the calculations are more precise and
489 the FPS aren't affected).*/
490 /*if( ! fps_fps < 50.0 )
493 jump = true;*/ /*FIXME: Implement this tweak right.*/
496 /* Time stops in pause mode */
497 if(game_pause || show_menu )
502 /* Set the time of the last update and the time of the current update */
503 last_update_time = update_time;
504 update_time = st_get_ticks();
506 /* Pause till next frame, if the machine running the game is too fast: */
507 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
508 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
509 if(last_update_time >= update_time - 12) {
511 update_time = st_get_ticks();
513 /*if((update_time - last_update_time) < 10)
514 SDL_Delay((11 - (update_time - last_update_time))/2);*/
517 if (time_left.check())
519 /* are we low on time ? */
520 if (time_left.get_left() < TIME_WARNING
521 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
523 set_current_music(HURRYUP_MUSIC);
524 play_current_music();
527 else if(tux->dying == DYING_NOT)
530 /* Calculate frames per second */
534 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
536 if(!fps_timer.check())
538 fps_timer.start(1000);
546 world->get_level()->free_gfx();
547 world->get_level()->cleanup();
548 world->get_level()->free_song();
553 /* Bounce a brick: */
554 void bumpbrick(float x, float y)
556 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
559 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
564 GameSession::drawstatus()
568 sprintf(str, "%d", player_status.score);
569 white_text->draw("SCORE", 0, 0, 1);
570 gold_text->draw(str, 96, 0, 1);
572 if(st_gl_mode != ST_GL_TEST)
574 sprintf(str, "%d", hs_score);
575 white_text->draw("HIGH", 0, 20, 1);
576 gold_text->draw(str, 96, 20, 1);
580 white_text->draw("Press ESC To Return",0,20,1);
583 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
585 sprintf(str, "%d", time_left.get_left() / 1000 );
586 white_text->draw("TIME", 224, 0, 1);
587 gold_text->draw(str, 304, 0, 1);
590 sprintf(str, "%d", player_status.distros);
591 white_text->draw("DISTROS", screen->h, 0, 1);
592 gold_text->draw(str, 608, 0, 1);
594 white_text->draw("LIVES", screen->h, 20, 1);
598 sprintf(str, "%2.1f", fps_fps);
599 white_text->draw("FPS", screen->h, 40, 1);
600 gold_text->draw(str, screen->h + 60, 40, 1);
603 for(int i= 0; i < player_status.lives; ++i)
605 tux_life->draw(565+(18*i),20);
610 GameSession::drawendscreen()
614 clearscreen(0, 0, 0);
616 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
618 sprintf(str, "SCORE: %d", player_status.score);
619 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
621 sprintf(str, "COINS: %d", player_status.distros);
622 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
627 wait_for_event(event,2000,5000,true);
631 GameSession::drawresultscreen(void)
635 clearscreen(0, 0, 0);
637 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
639 sprintf(str, "SCORE: %d", player_status.score);
640 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
642 sprintf(str, "DISTROS: %d", player_status.distros);
643 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
648 wait_for_event(event,2000,5000,true);
651 std::string slotinfo(int slot)
655 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
657 if (access(slotfile, F_OK) == 0)
658 sprintf(tmp,"Slot %d - Savegame",slot);
660 sprintf(tmp,"Slot %d - Free",slot);