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();
522 update_load_save_game_menu(save_game_menu, false);
525 update_load_save_game_menu(load_game_menu, true);
528 st_pause_ticks_stop();
533 else if(current_menu == options_menu)
535 process_options_menu();
537 else if(current_menu == load_game_menu )
539 process_load_game_menu();
544 /* Handle actions: */
546 if(!game_pause && !show_menu)
548 /*float z = frame_ratio;
552 if (action(frame_ratio) == 0)
554 /* == 0: no more lives */
555 /* == -1: continues */
567 if(debug_mode && debug_fps)
570 /*Draw the current scene to the screen */
571 /*If the machine running the game is too slow
572 skip the drawing of the frame (so the calculations are more precise and
573 the FPS aren't affected).*/
574 /*if( ! fps_fps < 50.0 )
577 jump = true;*/ /*FIXME: Implement this tweak right.*/
580 /* Time stops in pause mode */
581 if(game_pause || show_menu )
586 /* Set the time of the last update and the time of the current update */
587 last_update_time = update_time;
588 update_time = st_get_ticks();
590 /* Pause till next frame, if the machine running the game is too fast: */
591 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
592 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
593 if(last_update_time >= update_time - 12) {
595 update_time = st_get_ticks();
597 /*if((update_time - last_update_time) < 10)
598 SDL_Delay((11 - (update_time - last_update_time))/2);*/
601 if (time_left.check())
603 /* are we low on time ? */
604 if (time_left.get_left() < TIME_WARNING
605 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
607 set_current_music(HURRYUP_MUSIC);
608 play_current_music();
612 else if(tux.dying == DYING_NOT)
615 /* Calculate frames per second */
619 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
621 if(!fps_timer.check())
623 fps_timer.start(1000);
631 world->get_level()->free_gfx();
632 world->get_level()->cleanup();
633 world->get_level()->free_song();
635 world->arrays_free();
640 /* Bounce a brick: */
641 void bumpbrick(float x, float y)
643 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
646 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
651 GameSession::drawstatus()
655 sprintf(str, "%d", player_status.score);
656 white_text->draw("SCORE", 0, 0, 1);
657 gold_text->draw(str, 96, 0, 1);
659 if(st_gl_mode != ST_GL_TEST)
661 sprintf(str, "%d", hs_score);
662 white_text->draw("HIGH", 0, 20, 1);
663 gold_text->draw(str, 96, 20, 1);
667 white_text->draw("Press ESC To Return",0,20,1);
670 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
672 sprintf(str, "%d", time_left.get_left() / 1000 );
673 white_text->draw("TIME", 224, 0, 1);
674 gold_text->draw(str, 304, 0, 1);
677 sprintf(str, "%d", player_status.distros);
678 white_text->draw("DISTROS", screen->h, 0, 1);
679 gold_text->draw(str, 608, 0, 1);
681 white_text->draw("LIVES", screen->h, 20, 1);
685 sprintf(str, "%2.1f", fps_fps);
686 white_text->draw("FPS", screen->h, 40, 1);
687 gold_text->draw(str, screen->h + 60, 40, 1);
690 for(int i= 0; i < player_status.lives; ++i)
692 tux_life->draw(565+(18*i),20);
697 GameSession::drawendscreen()
701 clearscreen(0, 0, 0);
703 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
705 sprintf(str, "SCORE: %d", player_status.score);
706 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
708 sprintf(str, "COINS: %d", player_status.distros);
709 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
714 wait_for_event(event,2000,5000,true);
718 GameSession::drawresultscreen(void)
722 clearscreen(0, 0, 0);
724 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
726 sprintf(str, "SCORE: %d", player_status.score);
727 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
729 sprintf(str, "DISTROS: %d", player_status.distros);
730 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
735 wait_for_event(event,2000,5000,true);
738 std::string slotinfo(int slot)
745 sprintf(slotfile,"%s/slot%d.save",st_save_dir,slot);
747 fi = fopen(slotfile, "rb");
749 sprintf(tmp,"Slot %d - ",slot);
758 str[strlen(str)-1] = '\0';
760 strcat(tmp, " / Level:");
761 fread(&slot_level,sizeof(int),1,fi);
762 sprintf(str,"%d",slot_level);