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_TEST)
121 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
125 time_left.init(true);
129 GameSession::~GameSession()
135 GameSession::levelintro(void)
139 clearscreen(0, 0, 0);
141 sprintf(str, "%s", world->get_level()->name.c_str());
142 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
144 sprintf(str, "TUX x %d", player_status.lives);
145 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
147 sprintf(str, "by %s", world->get_level()->author.c_str());
148 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
154 wait_for_event(event,1000,3000,true);
159 GameSession::start_timers()
161 time_left.start(world->get_level()->time_left*1000);
162 st_pause_ticks_init();
163 update_time = st_get_ticks();
167 GameSession::on_escape_press()
169 if(st_gl_mode == ST_GL_TEST)
171 exit_status = LEVEL_ABORT;
173 else if (!Menu::current())
175 Menu::set_current(game_menu);
176 st_pause_ticks_stop();
181 GameSession::process_events()
183 Player& tux = *world->get_tux();
186 while (SDL_PollEvent(&event))
188 /* Check for menu-events, if the menu is shown */
191 Menu::current()->event(event);
197 case SDL_QUIT: /* Quit event - quit: */
198 st_abort("Received window close", "");
201 case SDL_KEYDOWN: /* A keypress! */
203 SDLKey key = event.key.keysym.sym;
205 if(tux.key_event(key,DOWN))
210 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
218 case SDL_KEYUP: /* A keyrelease! */
220 SDLKey key = event.key.keysym.sym;
222 if(tux.key_event(key, UP))
233 st_pause_ticks_stop();
238 st_pause_ticks_start();
245 tux.size = !tux.size;
248 tux.base.height = 64;
251 tux.base.height = 32;
256 player_status.distros += 50;
264 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
268 --player_status.lives;
272 player_status.score += 1000;
285 case SDL_JOYAXISMOTION:
286 switch(event.jaxis.axis)
289 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
291 tux.input.left = DOWN;
292 tux.input.right = UP;
294 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
297 tux.input.right = DOWN;
301 tux.input.left = DOWN;
302 tux.input.right = DOWN;
306 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
307 tux.input.down = DOWN;
308 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
318 case SDL_JOYBUTTONDOWN:
319 if (event.jbutton.button == JOY_A)
321 else if (event.jbutton.button == JOY_B)
322 tux.input.fire = DOWN;
323 else if (event.jbutton.button == JOY_START)
326 case SDL_JOYBUTTONUP:
327 if (event.jbutton.button == JOY_A)
329 else if (event.jbutton.button == JOY_B)
342 GameSession::check_end_conditions()
344 Player* tux = world->get_tux();
347 if (tux->base.x >= World::current()->get_level()->endpos
348 && World::current()->get_level()->endpos != 0)
350 exit_status = LEVEL_FINISHED;
354 // Check End conditions
357 player_status.lives -= 1;
359 if (player_status.lives < 0)
361 if(st_gl_mode != ST_GL_TEST)
364 exit_status = GAME_OVER;
367 { // Still has lives, so reset Tux to the levelstart
375 GameSession::action(double frame_ratio)
377 check_end_conditions();
379 if (exit_status == NONE)
381 // Update Tux and the World
382 world->action(frame_ratio);
394 int x = screen->h / 20;
395 for(int i = 0; i < x; ++i)
397 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);
399 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
400 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
405 Menu::current()->draw();
406 mouse_cursor->draw();
413 GameSession::ExitStatus
416 Menu::set_current(0);
417 Player* tux = world->get_tux();
422 global_frame_counter = 0;
425 fps_timer.init(true);
426 frame_timer.init(true);
428 last_update_time = st_get_ticks();
432 clearscreen(0, 0, 0);
436 play_current_music();
438 // Eat unneeded events
440 while (SDL_PollEvent(&event)) {}
444 float overlap = 0.0f;
445 while (exit_status == NONE)
447 /* Calculate the movement-factor */
448 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
450 if(!frame_timer.check())
452 frame_timer.start(25);
453 ++global_frame_counter;
457 tux->input.old_fire = tux->input.fire;
461 Menu* menu = Menu::current();
466 if(menu == game_menu)
468 switch (game_menu->check())
471 st_pause_ticks_stop();
474 st_pause_ticks_stop();
475 exit_status = LEVEL_ABORT;
479 else if(menu == options_menu)
481 process_options_menu();
483 else if(menu == load_game_menu )
485 process_load_game_menu();
490 if(!game_pause && !Menu::current())
492 frame_ratio *= game_speed;
493 frame_ratio += overlap;
494 while (frame_ratio > 0)
499 overlap = frame_ratio;
501 if (exit_status != NONE)
510 if(debug_mode && debug_fps)
513 /*Draw the current scene to the screen */
514 /*If the machine running the game is too slow
515 skip the drawing of the frame (so the calculations are more precise and
516 the FPS aren't affected).*/
517 /*if( ! fps_fps < 50.0 )
520 jump = true;*/ /*FIXME: Implement this tweak right.*/
523 /* Time stops in pause mode */
524 if(game_pause || Menu::current())
529 /* Set the time of the last update and the time of the current update */
530 last_update_time = update_time;
531 update_time = st_get_ticks();
533 /* Pause till next frame, if the machine running the game is too fast: */
534 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
535 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
536 if(last_update_time >= update_time - 12) {
538 update_time = st_get_ticks();
540 /*if((update_time - last_update_time) < 10)
541 SDL_Delay((11 - (update_time - last_update_time))/2);*/
544 if (time_left.check())
546 /* are we low on time ? */
547 if (time_left.get_left() < TIME_WARNING
548 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
550 set_current_music(HURRYUP_MUSIC);
551 play_current_music();
554 else if(tux->dying == DYING_NOT)
557 /* Calculate frames per second */
561 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
563 if(!fps_timer.check())
565 fps_timer.start(1000);
573 world->get_level()->free_gfx();
574 world->get_level()->cleanup();
575 world->get_level()->free_song();
580 /* Bounce a brick: */
581 void bumpbrick(float x, float y)
583 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
586 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
591 GameSession::drawstatus()
595 sprintf(str, "%d", player_status.score);
596 white_text->draw("SCORE", 0, 0, 1);
597 gold_text->draw(str, 96, 0, 1);
599 if(st_gl_mode == ST_GL_TEST)
601 white_text->draw("Press ESC To Return",0,20,1);
604 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
606 sprintf(str, "%d", time_left.get_left() / 1000 );
607 white_text->draw("TIME", 224, 0, 1);
608 gold_text->draw(str, 304, 0, 1);
611 sprintf(str, "%d", player_status.distros);
612 white_text->draw("DISTROS", screen->h, 0, 1);
613 gold_text->draw(str, 608, 0, 1);
615 white_text->draw("LIVES", screen->h, 20, 1);
619 sprintf(str, "%2.1f", fps_fps);
620 white_text->draw("FPS", screen->h, 40, 1);
621 gold_text->draw(str, screen->h + 60, 40, 1);
624 for(int i= 0; i < player_status.lives; ++i)
626 tux_life->draw(565+(18*i),20);
631 GameSession::drawendscreen()
635 clearscreen(0, 0, 0);
637 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
639 sprintf(str, "SCORE: %d", player_status.score);
640 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
642 sprintf(str, "COINS: %d", player_status.distros);
643 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
648 wait_for_event(event,2000,5000,true);
652 GameSession::drawresultscreen(void)
656 clearscreen(0, 0, 0);
658 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
660 sprintf(str, "SCORE: %d", player_status.score);
661 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
663 sprintf(str, "DISTROS: %d", player_status.distros);
664 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
669 wait_for_event(event,2000,5000,true);
672 std::string slotinfo(int slot)
676 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
678 if (access(slotfile, F_OK) == 0)
679 sprintf(tmp,"Slot %d - Savegame",slot);
681 sprintf(tmp,"Slot %d - Free",slot);