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 */
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 Player* tux = world->get_tux();
351 // Update Tux and the World
352 tux->action(frame_ratio);
353 world->action(frame_ratio);
365 int x = screen->h / 20;
366 for(int i = 0; i < x; ++i)
368 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);
370 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
371 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
376 menu_process_current();
377 mouse_cursor->draw();
384 GameSession::ExitStatus
387 Player* tux = world->get_tux();
392 global_frame_counter = 0;
395 fps_timer.init(true);
396 frame_timer.init(true);
398 last_update_time = st_get_ticks();
402 clearscreen(0, 0, 0);
406 play_current_music();
408 // Eat unneeded events
410 while (SDL_PollEvent(&event)) {}
414 while (exit_status == NONE)
416 /* Calculate the movement-factor */
417 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
418 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
419 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
421 if(!frame_timer.check())
423 frame_timer.start(25);
424 ++global_frame_counter;
428 tux->input.old_fire = tux->input.fire;
434 if(current_menu == game_menu)
436 switch (game_menu->check())
439 st_pause_ticks_stop();
443 //update_load_save_game_menu(save_game_menu);
446 update_load_save_game_menu(load_game_menu);
449 st_pause_ticks_stop();
450 exit_status = LEVEL_ABORT;
454 else if(current_menu == options_menu)
456 process_options_menu();
458 else if(current_menu == load_game_menu )
460 process_load_game_menu();
465 if(!game_pause && !show_menu)
468 if (exit_status != NONE)
477 if(debug_mode && debug_fps)
480 /*Draw the current scene to the screen */
481 /*If the machine running the game is too slow
482 skip the drawing of the frame (so the calculations are more precise and
483 the FPS aren't affected).*/
484 /*if( ! fps_fps < 50.0 )
487 jump = true;*/ /*FIXME: Implement this tweak right.*/
490 /* Time stops in pause mode */
491 if(game_pause || show_menu )
496 /* Set the time of the last update and the time of the current update */
497 last_update_time = update_time;
498 update_time = st_get_ticks();
500 /* Pause till next frame, if the machine running the game is too fast: */
501 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
502 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
503 if(last_update_time >= update_time - 12) {
505 update_time = st_get_ticks();
507 /*if((update_time - last_update_time) < 10)
508 SDL_Delay((11 - (update_time - last_update_time))/2);*/
511 if (time_left.check())
513 /* are we low on time ? */
514 if (time_left.get_left() < TIME_WARNING
515 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
517 set_current_music(HURRYUP_MUSIC);
518 play_current_music();
521 else if(tux->dying == DYING_NOT)
524 /* Calculate frames per second */
528 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
530 if(!fps_timer.check())
532 fps_timer.start(1000);
540 world->get_level()->free_gfx();
541 world->get_level()->cleanup();
542 world->get_level()->free_song();
547 /* Bounce a brick: */
548 void bumpbrick(float x, float y)
550 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
553 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
558 GameSession::drawstatus()
562 sprintf(str, "%d", player_status.score);
563 white_text->draw("SCORE", 0, 0, 1);
564 gold_text->draw(str, 96, 0, 1);
566 if(st_gl_mode != ST_GL_TEST)
568 sprintf(str, "%d", hs_score);
569 white_text->draw("HIGH", 0, 20, 1);
570 gold_text->draw(str, 96, 20, 1);
574 white_text->draw("Press ESC To Return",0,20,1);
577 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
579 sprintf(str, "%d", time_left.get_left() / 1000 );
580 white_text->draw("TIME", 224, 0, 1);
581 gold_text->draw(str, 304, 0, 1);
584 sprintf(str, "%d", player_status.distros);
585 white_text->draw("DISTROS", screen->h, 0, 1);
586 gold_text->draw(str, 608, 0, 1);
588 white_text->draw("LIVES", screen->h, 20, 1);
592 sprintf(str, "%2.1f", fps_fps);
593 white_text->draw("FPS", screen->h, 40, 1);
594 gold_text->draw(str, screen->h + 60, 40, 1);
597 for(int i= 0; i < player_status.lives; ++i)
599 tux_life->draw(565+(18*i),20);
604 GameSession::drawendscreen()
608 clearscreen(0, 0, 0);
610 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
612 sprintf(str, "SCORE: %d", player_status.score);
613 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
615 sprintf(str, "COINS: %d", player_status.distros);
616 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
621 wait_for_event(event,2000,5000,true);
625 GameSession::drawresultscreen(void)
629 clearscreen(0, 0, 0);
631 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
633 sprintf(str, "SCORE: %d", player_status.score);
634 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
636 sprintf(str, "DISTROS: %d", player_status.distros);
637 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
642 wait_for_event(event,2000,5000,true);
645 std::string slotinfo(int slot)
649 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
651 if (access(slotfile, F_OK) == 0)
652 sprintf(tmp,"Slot %d - Savegame",slot);
654 sprintf(tmp,"Slot %d - Free",slot);