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);
173 st_pause_ticks_stop();
178 GameSession::process_events()
180 Player& tux = *world->get_tux();
183 while (SDL_PollEvent(&event))
185 /* Check for menu-events, if the menu is shown */
188 Menu::current()->event(event);
194 case SDL_QUIT: /* Quit event - quit: */
195 st_abort("Received window close", "");
198 case SDL_KEYDOWN: /* A keypress! */
200 SDLKey key = event.key.keysym.sym;
202 if(tux.key_event(key,DOWN))
207 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
215 case SDL_KEYUP: /* A keyrelease! */
217 SDLKey key = event.key.keysym.sym;
219 if(tux.key_event(key, UP))
230 st_pause_ticks_stop();
235 st_pause_ticks_start();
242 tux.size = !tux.size;
245 tux.base.height = 64;
248 tux.base.height = 32;
253 player_status.distros += 50;
261 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
265 --player_status.lives;
269 player_status.score += 1000;
282 case SDL_JOYAXISMOTION:
283 if (event.jaxis.axis == JOY_X)
285 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
287 tux.input.left = DOWN;
288 tux.input.right = UP;
290 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
293 tux.input.right = DOWN;
297 tux.input.left = DOWN;
298 tux.input.right = DOWN;
301 else if (event.jaxis.axis == JOY_Y)
303 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
304 tux.input.down = DOWN;
305 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
312 case SDL_JOYBUTTONDOWN:
313 if (event.jbutton.button == JOY_A)
315 else if (event.jbutton.button == JOY_B)
316 tux.input.fire = DOWN;
317 else if (event.jbutton.button == JOY_START)
320 case SDL_JOYBUTTONUP:
321 if (event.jbutton.button == JOY_A)
323 else if (event.jbutton.button == JOY_B)
336 GameSession::check_end_conditions()
338 Player* tux = world->get_tux();
341 if (tux->base.x >= World::current()->get_level()->endpos
342 && World::current()->get_level()->endpos != 0)
344 exit_status = LEVEL_FINISHED;
348 // Check End conditions
351 player_status.lives -= 1;
353 if (player_status.lives < 0)
355 if(st_gl_mode != ST_GL_TEST)
358 exit_status = GAME_OVER;
361 { // Still has lives, so reset Tux to the levelstart
369 GameSession::action(double frame_ratio)
371 check_end_conditions();
373 if (exit_status == NONE)
375 // Update Tux and the World
376 world->action(frame_ratio);
388 int x = screen->h / 20;
389 for(int i = 0; i < x; ++i)
391 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);
393 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
394 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
399 Menu::current()->draw();
400 mouse_cursor->draw();
407 GameSession::ExitStatus
410 Menu::set_current(0);
411 Player* tux = world->get_tux();
416 global_frame_counter = 0;
419 fps_timer.init(true);
420 frame_timer.init(true);
422 last_update_time = st_get_ticks();
426 clearscreen(0, 0, 0);
430 play_current_music();
432 // Eat unneeded events
434 while (SDL_PollEvent(&event)) {}
438 float overlap = 0.0f;
439 while (exit_status == NONE)
441 /* Calculate the movement-factor */
442 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
444 if(!frame_timer.check())
446 frame_timer.start(25);
447 ++global_frame_counter;
451 tux->input.old_fire = tux->input.fire;
455 Menu* menu = Menu::current();
460 if(menu == game_menu)
462 switch (game_menu->check())
465 st_pause_ticks_stop();
468 st_pause_ticks_stop();
469 exit_status = LEVEL_ABORT;
473 else if(menu == options_menu)
475 process_options_menu();
477 else if(menu == load_game_menu )
479 process_load_game_menu();
484 if(!game_pause && !Menu::current())
486 frame_ratio *= game_speed;
487 frame_ratio += overlap;
488 while (frame_ratio > 0)
493 overlap = frame_ratio;
495 if (exit_status != NONE)
504 if(debug_mode && debug_fps)
507 /*Draw the current scene to the screen */
508 /*If the machine running the game is too slow
509 skip the drawing of the frame (so the calculations are more precise and
510 the FPS aren't affected).*/
511 /*if( ! fps_fps < 50.0 )
514 jump = true;*/ /*FIXME: Implement this tweak right.*/
517 /* Time stops in pause mode */
518 if(game_pause || Menu::current())
523 /* Set the time of the last update and the time of the current update */
524 last_update_time = update_time;
525 update_time = st_get_ticks();
527 /* Pause till next frame, if the machine running the game is too fast: */
528 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
529 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
530 if(last_update_time >= update_time - 12) {
532 update_time = st_get_ticks();
534 /*if((update_time - last_update_time) < 10)
535 SDL_Delay((11 - (update_time - last_update_time))/2);*/
538 if (time_left.check())
540 /* are we low on time ? */
541 if (time_left.get_left() < TIME_WARNING
542 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
544 set_current_music(HURRYUP_MUSIC);
545 play_current_music();
548 else if(tux->dying == DYING_NOT)
551 /* Calculate frames per second */
555 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
557 if(!fps_timer.check())
559 fps_timer.start(1000);
567 world->get_level()->free_gfx();
568 world->get_level()->cleanup();
569 world->get_level()->free_song();
574 /* Bounce a brick: */
575 void bumpbrick(float x, float y)
577 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
580 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
585 GameSession::drawstatus()
589 sprintf(str, "%d", player_status.score);
590 white_text->draw("SCORE", 0, 0, 1);
591 gold_text->draw(str, 96, 0, 1);
593 if(st_gl_mode == ST_GL_TEST)
595 white_text->draw("Press ESC To Return",0,20,1);
598 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
600 sprintf(str, "%d", time_left.get_left() / 1000 );
601 white_text->draw("TIME", 224, 0, 1);
602 gold_text->draw(str, 304, 0, 1);
605 sprintf(str, "%d", player_status.distros);
606 white_text->draw("DISTROS", screen->h, 0, 1);
607 gold_text->draw(str, 608, 0, 1);
609 white_text->draw("LIVES", screen->h, 20, 1);
613 sprintf(str, "%2.1f", fps_fps);
614 white_text->draw("FPS", screen->h, 40, 1);
615 gold_text->draw(str, screen->h + 60, 40, 1);
618 for(int i= 0; i < player_status.lives; ++i)
620 tux_life->draw(565+(18*i),20);
625 GameSession::drawendscreen()
629 clearscreen(0, 0, 0);
631 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
633 sprintf(str, "SCORE: %d", player_status.score);
634 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
636 sprintf(str, "COINS: %d", player_status.distros);
637 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
642 wait_for_event(event,2000,5000,true);
646 GameSession::drawresultscreen(void)
650 clearscreen(0, 0, 0);
652 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
654 sprintf(str, "SCORE: %d", player_status.score);
655 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
657 sprintf(str, "DISTROS: %d", player_status.distros);
658 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
663 wait_for_event(event,2000,5000,true);
666 std::string slotinfo(int slot)
670 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
672 if (access(slotfile, F_OK) == 0)
673 sprintf(tmp,"Slot %d - Savegame",slot);
675 sprintf(tmp,"Slot %d - Free",slot);