4 // Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 // Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
6 // Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <sys/types.h>
44 #include "high_scores.h"
52 #include "collision.h"
54 #include "particlesystem.h"
55 #include "resources.h"
57 GameSession* GameSession::current_ = 0;
59 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
60 : world(0), st_gl_mode(mode), levelnb(levelnb_), subset(subset_)
67 GameSession::restart_level()
73 frame_timer.init(true);
78 { // Tux has lost a life, so we try to respawn him at the nearest reset point
79 old_x_pos = world->get_tux()->base.x;
84 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
86 world = new World(subset);
88 else if (st_gl_mode == ST_GL_DEMO_GAME)
90 world = new World(subset);
94 world = new World(subset, levelnb);
97 // Set Tux to the nearest reset point
100 ResetPoint best_reset_point = { -1, -1 };
101 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
102 i != get_level()->reset_points.end(); ++i)
104 if (i->x < old_x_pos && best_reset_point.x < i->x)
105 best_reset_point = *i;
108 if (best_reset_point.x != -1)
110 world->get_tux()->base.x = best_reset_point.x;
111 world->get_tux()->base.y = best_reset_point.y;
116 if (st_gl_mode != ST_GL_DEMO_GAME)
118 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
122 time_left.init(true);
126 GameSession::~GameSession()
132 GameSession::levelintro(void)
136 clearscreen(0, 0, 0);
138 sprintf(str, "%s", world->get_level()->name.c_str());
139 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
141 sprintf(str, "TUX x %d", player_status.lives);
142 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
144 sprintf(str, "by %s", world->get_level()->author.c_str());
145 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
151 wait_for_event(event,1000,3000,true);
156 GameSession::start_timers()
158 time_left.start(world->get_level()->time_left*1000);
159 st_pause_ticks_init();
160 update_time = st_get_ticks();
164 GameSession::on_escape_press()
166 if(st_gl_mode == ST_GL_TEST)
168 exit_status = LEVEL_ABORT;
170 else if (!Menu::current())
172 Menu::set_current(game_menu);
177 GameSession::process_events()
179 Player& tux = *world->get_tux();
182 while (SDL_PollEvent(&event))
184 /* Check for menu-events, if the menu is shown */
187 Menu::current()->event(event);
188 st_pause_ticks_start();
192 st_pause_ticks_stop();
196 case SDL_QUIT: /* Quit event - quit: */
197 st_abort("Received window close", "");
200 case SDL_KEYDOWN: /* A keypress! */
202 SDLKey key = event.key.keysym.sym;
204 if(tux.key_event(key,DOWN))
209 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
217 case SDL_KEYUP: /* A keyrelease! */
219 SDLKey key = event.key.keysym.sym;
221 if(tux.key_event(key, UP))
232 st_pause_ticks_stop();
237 st_pause_ticks_start();
244 tux.size = !tux.size;
247 tux.base.height = 64;
250 tux.base.height = 32;
255 player_status.distros += 50;
263 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
267 --player_status.lives;
271 player_status.score += 1000;
284 case SDL_JOYAXISMOTION:
285 if (event.jaxis.axis == joystick_keymap.x_axis)
287 if (event.jaxis.value < -joystick_keymap.dead_zone)
289 tux.input.left = DOWN;
290 tux.input.right = UP;
292 else if (event.jaxis.value > joystick_keymap.dead_zone)
295 tux.input.right = DOWN;
299 tux.input.left = DOWN;
300 tux.input.right = DOWN;
303 else if (event.jaxis.axis == joystick_keymap.y_axis)
305 if (event.jaxis.value > joystick_keymap.dead_zone)
306 tux.input.down = DOWN;
307 else if (event.jaxis.value < -joystick_keymap.dead_zone)
314 case SDL_JOYBUTTONDOWN:
315 if (event.jbutton.button == joystick_keymap.a_button)
317 else if (event.jbutton.button == joystick_keymap.b_button)
318 tux.input.fire = DOWN;
319 else if (event.jbutton.button == joystick_keymap.start_button)
322 case SDL_JOYBUTTONUP:
323 if (event.jbutton.button == joystick_keymap.a_button)
325 else if (event.jbutton.button == joystick_keymap.b_button)
338 GameSession::check_end_conditions()
340 Player* tux = world->get_tux();
343 if (tux->base.x >= World::current()->get_level()->endpos
344 && World::current()->get_level()->endpos != 0)
346 exit_status = LEVEL_FINISHED;
350 // Check End conditions
353 player_status.lives -= 1;
355 if (player_status.lives < 0)
357 if(st_gl_mode != ST_GL_TEST)
360 exit_status = GAME_OVER;
363 { // Still has lives, so reset Tux to the levelstart
371 GameSession::action(double frame_ratio)
373 check_end_conditions();
375 if (exit_status == NONE)
377 // Update Tux and the World
378 world->action(frame_ratio);
390 int x = screen->h / 20;
391 for(int i = 0; i < x; ++i)
393 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);
395 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
396 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
401 Menu::current()->draw();
402 mouse_cursor->draw();
409 GameSession::ExitStatus
412 Menu::set_current(0);
413 Player* tux = world->get_tux();
418 global_frame_counter = 0;
421 fps_timer.init(true);
422 frame_timer.init(true);
424 last_update_time = st_get_ticks();
428 clearscreen(0, 0, 0);
432 play_current_music();
434 // Eat unneeded events
436 while (SDL_PollEvent(&event)) {}
440 float overlap = 0.0f;
441 while (exit_status == NONE)
443 /* Calculate the movement-factor */
444 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
446 if(!frame_timer.check())
448 frame_timer.start(25);
449 ++global_frame_counter;
453 tux->input.old_fire = tux->input.fire;
457 Menu* menu = Menu::current();
462 if(menu == game_menu)
464 switch (game_menu->check())
467 st_pause_ticks_stop();
470 st_pause_ticks_stop();
471 exit_status = LEVEL_ABORT;
475 else if(menu == options_menu)
477 process_options_menu();
479 else if(menu == load_game_menu )
481 process_load_game_menu();
486 if(!game_pause && !Menu::current())
488 frame_ratio *= game_speed;
489 frame_ratio += overlap;
490 while (frame_ratio > 0)
495 overlap = frame_ratio;
497 if (exit_status != NONE)
506 if(debug_mode && debug_fps)
509 /*Draw the current scene to the screen */
510 /*If the machine running the game is too slow
511 skip the drawing of the frame (so the calculations are more precise and
512 the FPS aren't affected).*/
513 /*if( ! fps_fps < 50.0 )
516 jump = true;*/ /*FIXME: Implement this tweak right.*/
519 /* Time stops in pause mode */
520 if(game_pause || Menu::current())
525 /* Set the time of the last update and the time of the current update */
526 last_update_time = update_time;
527 update_time = st_get_ticks();
529 /* Pause till next frame, if the machine running the game is too fast: */
530 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
531 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
532 if(last_update_time >= update_time - 12) {
534 update_time = st_get_ticks();
536 /*if((update_time - last_update_time) < 10)
537 SDL_Delay((11 - (update_time - last_update_time))/2);*/
540 if (time_left.check())
542 /* are we low on time ? */
543 if (time_left.get_left() < TIME_WARNING
544 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
546 set_current_music(HURRYUP_MUSIC);
547 play_current_music();
550 else if(tux->dying == DYING_NOT)
553 /* Calculate frames per second */
557 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
559 if(!fps_timer.check())
561 fps_timer.start(1000);
569 world->get_level()->free_gfx();
570 world->get_level()->cleanup();
571 world->get_level()->free_song();
576 /* Bounce a brick: */
577 void bumpbrick(float x, float y)
579 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
582 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
587 GameSession::drawstatus()
591 sprintf(str, "%d", player_status.score);
592 white_text->draw("SCORE", 0, 0, 1);
593 gold_text->draw(str, 96, 0, 1);
595 if(st_gl_mode == ST_GL_TEST)
597 white_text->draw("Press ESC To Return",0,20,1);
600 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
602 sprintf(str, "%d", time_left.get_left() / 1000 );
603 white_text->draw("TIME", 224, 0, 1);
604 gold_text->draw(str, 304, 0, 1);
607 sprintf(str, "%d", player_status.distros);
608 white_text->draw("DISTROS", screen->h, 0, 1);
609 gold_text->draw(str, 608, 0, 1);
611 white_text->draw("LIVES", screen->h, 20, 1);
615 sprintf(str, "%2.1f", fps_fps);
616 white_text->draw("FPS", screen->h, 40, 1);
617 gold_text->draw(str, screen->h + 60, 40, 1);
620 for(int i= 0; i < player_status.lives; ++i)
622 tux_life->draw(565+(18*i),20);
627 GameSession::drawendscreen()
631 clearscreen(0, 0, 0);
633 blue_text->drawf("GAMEOVER", 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, "COINS: %d", player_status.distros);
639 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
644 wait_for_event(event,2000,5000,true);
648 GameSession::drawresultscreen(void)
652 clearscreen(0, 0, 0);
654 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
656 sprintf(str, "SCORE: %d", player_status.score);
657 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
659 sprintf(str, "DISTROS: %d", player_status.distros);
660 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
665 wait_for_event(event,2000,5000,true);
668 std::string slotinfo(int slot)
672 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
674 if (access(slotfile, F_OK) == 0)
675 sprintf(tmp,"Slot %d - Savegame",slot);
677 sprintf(tmp,"Slot %d - Free",slot);