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
322 player_status.lives -= 1;
324 if (player_status.lives < 0)
326 if(st_gl_mode != ST_GL_TEST)
329 if(st_gl_mode != ST_GL_TEST)
331 // FIXME: highscore soving doesn't make sense in its
333 //if (player_status.score > hs_score)
334 //save_hs(player_status.score);
337 exit_status = GAME_OVER;
340 { // Still has lives, so reset Tux to the levelstart
348 GameSession::action(double frame_ratio)
350 check_end_conditions();
352 if (exit_status == NONE)
354 // Update Tux and the World
355 world->action(frame_ratio);
367 int x = screen->h / 20;
368 for(int i = 0; i < x; ++i)
370 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);
372 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
373 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
378 menu_process_current();
379 mouse_cursor->draw();
386 GameSession::ExitStatus
389 Player* tux = world->get_tux();
394 global_frame_counter = 0;
397 fps_timer.init(true);
398 frame_timer.init(true);
400 last_update_time = st_get_ticks();
404 clearscreen(0, 0, 0);
408 play_current_music();
410 // Eat unneeded events
412 while (SDL_PollEvent(&event)) {}
416 float overlap = 0.0f;
417 while (exit_status == NONE)
419 /* Calculate the movement-factor */
420 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
422 if(!frame_timer.check())
424 frame_timer.start(25);
425 ++global_frame_counter;
429 tux->input.old_fire = tux->input.fire;
435 if(current_menu == game_menu)
437 switch (game_menu->check())
440 st_pause_ticks_stop();
443 st_pause_ticks_stop();
444 exit_status = LEVEL_ABORT;
448 else if(current_menu == options_menu)
450 process_options_menu();
452 else if(current_menu == load_game_menu )
454 process_load_game_menu();
459 if(!game_pause && !show_menu)
461 frame_ratio *= game_speed;
462 frame_ratio += overlap;
463 while (frame_ratio > 0)
468 overlap = frame_ratio;
470 if (exit_status != NONE)
479 if(debug_mode && debug_fps)
482 /*Draw the current scene to the screen */
483 /*If the machine running the game is too slow
484 skip the drawing of the frame (so the calculations are more precise and
485 the FPS aren't affected).*/
486 /*if( ! fps_fps < 50.0 )
489 jump = true;*/ /*FIXME: Implement this tweak right.*/
492 /* Time stops in pause mode */
493 if(game_pause || show_menu )
498 /* Set the time of the last update and the time of the current update */
499 last_update_time = update_time;
500 update_time = st_get_ticks();
502 /* Pause till next frame, if the machine running the game is too fast: */
503 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
504 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
505 if(last_update_time >= update_time - 12) {
507 update_time = st_get_ticks();
509 /*if((update_time - last_update_time) < 10)
510 SDL_Delay((11 - (update_time - last_update_time))/2);*/
513 if (time_left.check())
515 /* are we low on time ? */
516 if (time_left.get_left() < TIME_WARNING
517 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
519 set_current_music(HURRYUP_MUSIC);
520 play_current_music();
523 else if(tux->dying == DYING_NOT)
526 /* Calculate frames per second */
530 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
532 if(!fps_timer.check())
534 fps_timer.start(1000);
542 world->get_level()->free_gfx();
543 world->get_level()->cleanup();
544 world->get_level()->free_song();
549 /* Bounce a brick: */
550 void bumpbrick(float x, float y)
552 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
555 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
560 GameSession::drawstatus()
564 sprintf(str, "%d", player_status.score);
565 white_text->draw("SCORE", 0, 0, 1);
566 gold_text->draw(str, 96, 0, 1);
568 if(st_gl_mode != ST_GL_TEST)
570 sprintf(str, "%d", hs_score);
571 white_text->draw("HIGH", 0, 20, 1);
572 gold_text->draw(str, 96, 20, 1);
576 white_text->draw("Press ESC To Return",0,20,1);
579 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
581 sprintf(str, "%d", time_left.get_left() / 1000 );
582 white_text->draw("TIME", 224, 0, 1);
583 gold_text->draw(str, 304, 0, 1);
586 sprintf(str, "%d", player_status.distros);
587 white_text->draw("DISTROS", screen->h, 0, 1);
588 gold_text->draw(str, 608, 0, 1);
590 white_text->draw("LIVES", screen->h, 20, 1);
594 sprintf(str, "%2.1f", fps_fps);
595 white_text->draw("FPS", screen->h, 40, 1);
596 gold_text->draw(str, screen->h + 60, 40, 1);
599 for(int i= 0; i < player_status.lives; ++i)
601 tux_life->draw(565+(18*i),20);
606 GameSession::drawendscreen()
610 clearscreen(0, 0, 0);
612 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
614 sprintf(str, "SCORE: %d", player_status.score);
615 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
617 sprintf(str, "COINS: %d", player_status.distros);
618 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
623 wait_for_event(event,2000,5000,true);
627 GameSession::drawresultscreen(void)
631 clearscreen(0, 0, 0);
633 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
635 sprintf(str, "SCORE: %d", player_status.score);
636 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
638 sprintf(str, "DISTROS: %d", player_status.distros);
639 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
644 wait_for_event(event,2000,5000,true);
647 std::string slotinfo(int slot)
651 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
653 if (access(slotfile, F_OK) == 0)
654 sprintf(tmp,"Slot %d - Savegame",slot);
656 sprintf(tmp,"Slot %d - Free",slot);