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;
55 GameSession::GameSession()
61 GameSession::GameSession(const std::string& filename)
65 //assert(!"Don't call me");
71 frame_timer.init(true);
73 world->load(filename);
76 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
87 frame_timer.init(true);
93 world->set_defaults();
95 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
97 if (world->load(subset))
102 if(world->load(subset, levelnb) != 0)
106 world->get_level()->load_gfx();
108 world->activate_bad_guys();
109 world->activate_particle_systems();
110 world->get_level()->load_song();
112 if(st_gl_mode != ST_GL_TEST)
115 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
118 time_left.init(true);
122 GameSession::~GameSession()
128 GameSession::levelintro(void)
132 clearscreen(0, 0, 0);
134 sprintf(str, "LEVEL %d", levelnb);
135 blue_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
137 sprintf(str, "%s", world->get_level()->name.c_str());
138 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
140 sprintf(str, "TUX x %d", player_status.lives);
141 white_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
143 sprintf(str, "by %s", world->get_level()->author.c_str());
144 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
150 wait_for_event(event,1000,3000,true);
155 GameSession::start_timers()
157 time_left.start(world->get_level()->time_left*1000);
158 st_pause_ticks_init();
159 update_time = st_get_ticks();
163 GameSession::process_events()
165 Player& tux = *world->get_tux();
168 while (SDL_PollEvent(&event))
170 /* Check for menu-events, if the menu is shown */
172 current_menu->event(event);
176 case SDL_QUIT: /* Quit event - quit: */
179 case SDL_KEYDOWN: /* A keypress! */
181 SDLKey key = event.key.keysym.sym;
183 if(tux.key_event(key,DOWN))
188 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
191 if(st_gl_mode == ST_GL_TEST)
195 Menu::set_current(game_menu);
197 st_pause_ticks_stop();
201 Menu::set_current(game_menu);
203 st_pause_ticks_start();
212 case SDL_KEYUP: /* A keyrelease! */
214 SDLKey key = event.key.keysym.sym;
216 if(tux.key_event(key, UP))
227 st_pause_ticks_stop();
232 st_pause_ticks_start();
239 tux.size = !tux.size;
242 tux.base.height = 64;
245 tux.base.height = 32;
250 player_status.distros += 50;
254 player_status.next_level = 1;
262 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
266 --player_status.lives;
270 player_status.score += 1000;
283 case SDL_JOYAXISMOTION:
284 switch(event.jaxis.axis)
287 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
289 tux.input.left = DOWN;
290 tux.input.right = UP;
292 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
295 tux.input.right = DOWN;
299 tux.input.left = DOWN;
300 tux.input.right = DOWN;
304 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
305 tux.input.down = DOWN;
306 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
316 case SDL_JOYBUTTONDOWN:
317 if (event.jbutton.button == JOY_A)
319 else if (event.jbutton.button == JOY_B)
320 tux.input.fire = DOWN;
322 case SDL_JOYBUTTONUP:
323 if (event.jbutton.button == JOY_A)
325 else if (event.jbutton.button == JOY_B)
339 GameSession::action(double frame_ratio)
341 Player& tux = *world->get_tux();
343 if (tux.is_dead() || player_status.next_level)
345 /* Tux either died, or reached the end of a level! */
348 if (player_status.next_level)
350 /* End of a level! */
352 player_status.next_level = 0;
353 if(st_gl_mode != ST_GL_TEST)
359 world->get_level()->free_gfx();
360 world->get_level()->cleanup();
361 world->get_level()->free_song();
362 world->arrays_free();
372 /* No more lives!? */
374 if (player_status.lives < 0)
376 if(st_gl_mode != ST_GL_TEST)
379 if(st_gl_mode != ST_GL_TEST)
381 if (player_status.score > hs_score)
382 save_hs(player_status.score);
385 world->get_level()->free_gfx();
386 world->get_level()->cleanup();
387 world->get_level()->free_song();
388 world->arrays_free();
391 } /* if (lives < 0) */
394 /* Either way, (re-)load the (next) level... */
396 world->set_defaults();
398 world->get_level()->cleanup();
400 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
402 if(world->get_level()->load(subset) != 0)
407 if(world->get_level()->load(subset, levelnb) != 0)
411 world->arrays_free();
412 world->activate_bad_guys();
413 world->activate_particle_systems();
415 world->get_level()->free_gfx();
416 world->get_level()->load_gfx();
417 world->get_level()->free_song();
418 world->get_level()->load_song();
420 if(st_gl_mode != ST_GL_TEST)
424 play_current_music();
427 tux.action(frame_ratio);
429 world->action(frame_ratio);
442 int x = screen->h / 20;
443 for(int i = 0; i < x; ++i)
445 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);
447 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
448 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
453 menu_process_current();
454 mouse_cursor->draw();
464 Player& tux = *world->get_tux();
470 global_frame_counter = 0;
473 fps_timer.init(true);
474 frame_timer.init(true);
476 last_update_time = st_get_ticks();
480 clearscreen(0, 0, 0);
484 play_current_music();
486 // Eat unneeded events
488 while (SDL_PollEvent(&event)) {}
494 while (!done && !quit)
496 /* Calculate the movement-factor */
497 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
498 if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
499 frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
501 if(!frame_timer.check())
503 frame_timer.start(25);
504 ++global_frame_counter;
508 tux.input.old_fire = tux.input.fire;
514 if(current_menu == game_menu)
516 switch (game_menu->check())
519 st_pause_ticks_stop();
523 //update_load_save_game_menu(save_game_menu);
526 update_load_save_game_menu(load_game_menu);
529 st_pause_ticks_stop();
534 else if(current_menu == options_menu)
536 process_options_menu();
538 else if(current_menu == load_game_menu )
540 process_load_game_menu();
545 /* Handle actions: */
547 if(!game_pause && !show_menu)
549 /*float z = frame_ratio;
553 if (action(frame_ratio) == 0)
555 /* == 0: no more lives */
556 /* == -1: continues */
568 if(debug_mode && debug_fps)
571 /*Draw the current scene to the screen */
572 /*If the machine running the game is too slow
573 skip the drawing of the frame (so the calculations are more precise and
574 the FPS aren't affected).*/
575 /*if( ! fps_fps < 50.0 )
578 jump = true;*/ /*FIXME: Implement this tweak right.*/
581 /* Time stops in pause mode */
582 if(game_pause || show_menu )
587 /* Set the time of the last update and the time of the current update */
588 last_update_time = update_time;
589 update_time = st_get_ticks();
591 /* Pause till next frame, if the machine running the game is too fast: */
592 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
593 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
594 if(last_update_time >= update_time - 12) {
596 update_time = st_get_ticks();
598 /*if((update_time - last_update_time) < 10)
599 SDL_Delay((11 - (update_time - last_update_time))/2);*/
602 if (time_left.check())
604 /* are we low on time ? */
605 if (time_left.get_left() < TIME_WARNING
606 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
608 set_current_music(HURRYUP_MUSIC);
609 play_current_music();
613 else if(tux.dying == DYING_NOT)
616 /* Calculate frames per second */
620 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
622 if(!fps_timer.check())
624 fps_timer.start(1000);
632 world->get_level()->free_gfx();
633 world->get_level()->cleanup();
634 world->get_level()->free_song();
636 world->arrays_free();
641 /* Bounce a brick: */
642 void bumpbrick(float x, float y)
644 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
647 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
652 GameSession::drawstatus()
656 sprintf(str, "%d", player_status.score);
657 white_text->draw("SCORE", 0, 0, 1);
658 gold_text->draw(str, 96, 0, 1);
660 if(st_gl_mode != ST_GL_TEST)
662 sprintf(str, "%d", hs_score);
663 white_text->draw("HIGH", 0, 20, 1);
664 gold_text->draw(str, 96, 20, 1);
668 white_text->draw("Press ESC To Return",0,20,1);
671 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
673 sprintf(str, "%d", time_left.get_left() / 1000 );
674 white_text->draw("TIME", 224, 0, 1);
675 gold_text->draw(str, 304, 0, 1);
678 sprintf(str, "%d", player_status.distros);
679 white_text->draw("DISTROS", screen->h, 0, 1);
680 gold_text->draw(str, 608, 0, 1);
682 white_text->draw("LIVES", screen->h, 20, 1);
686 sprintf(str, "%2.1f", fps_fps);
687 white_text->draw("FPS", screen->h, 40, 1);
688 gold_text->draw(str, screen->h + 60, 40, 1);
691 for(int i= 0; i < player_status.lives; ++i)
693 tux_life->draw(565+(18*i),20);
698 GameSession::drawendscreen()
702 clearscreen(0, 0, 0);
704 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
706 sprintf(str, "SCORE: %d", player_status.score);
707 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
709 sprintf(str, "COINS: %d", player_status.distros);
710 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
715 wait_for_event(event,2000,5000,true);
719 GameSession::drawresultscreen(void)
723 clearscreen(0, 0, 0);
725 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
727 sprintf(str, "SCORE: %d", player_status.score);
728 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
730 sprintf(str, "DISTROS: %d", player_status.distros);
731 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
736 wait_for_event(event,2000,5000,true);
739 std::string slotinfo(int slot)
743 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
745 if (access(slotfile, F_OK) == 0)
746 sprintf(tmp,"Slot %d - Savegame",slot);
748 sprintf(tmp,"Slot %d - Free",slot);