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 switch(event.jaxis.axis)
286 if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
288 tux.input.left = DOWN;
289 tux.input.right = UP;
291 else if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
294 tux.input.right = DOWN;
298 tux.input.left = DOWN;
299 tux.input.right = DOWN;
303 if (event.jaxis.value > JOYSTICK_DEAD_ZONE)
304 tux.input.down = DOWN;
305 else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE)
315 case SDL_JOYBUTTONDOWN:
316 if (event.jbutton.button == JOY_A)
318 else if (event.jbutton.button == JOY_B)
319 tux.input.fire = DOWN;
320 else if (event.jbutton.button == JOY_START)
323 case SDL_JOYBUTTONUP:
324 if (event.jbutton.button == JOY_A)
326 else if (event.jbutton.button == JOY_B)
339 GameSession::check_end_conditions()
341 Player* tux = world->get_tux();
344 if (tux->base.x >= World::current()->get_level()->endpos
345 && World::current()->get_level()->endpos != 0)
347 exit_status = LEVEL_FINISHED;
351 // Check End conditions
354 player_status.lives -= 1;
356 if (player_status.lives < 0)
358 if(st_gl_mode != ST_GL_TEST)
361 exit_status = GAME_OVER;
364 { // Still has lives, so reset Tux to the levelstart
372 GameSession::action(double frame_ratio)
374 check_end_conditions();
376 if (exit_status == NONE)
378 // Update Tux and the World
379 world->action(frame_ratio);
391 int x = screen->h / 20;
392 for(int i = 0; i < x; ++i)
394 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);
396 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
397 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
402 Menu::current()->draw();
403 mouse_cursor->draw();
410 GameSession::ExitStatus
413 Menu::set_current(0);
414 Player* tux = world->get_tux();
419 global_frame_counter = 0;
422 fps_timer.init(true);
423 frame_timer.init(true);
425 last_update_time = st_get_ticks();
429 clearscreen(0, 0, 0);
433 play_current_music();
435 // Eat unneeded events
437 while (SDL_PollEvent(&event)) {}
441 float overlap = 0.0f;
442 while (exit_status == NONE)
444 /* Calculate the movement-factor */
445 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
447 if(!frame_timer.check())
449 frame_timer.start(25);
450 ++global_frame_counter;
454 tux->input.old_fire = tux->input.fire;
458 Menu* menu = Menu::current();
463 if(menu == game_menu)
465 switch (game_menu->check())
468 st_pause_ticks_stop();
471 st_pause_ticks_stop();
472 exit_status = LEVEL_ABORT;
476 else if(menu == options_menu)
478 process_options_menu();
480 else if(menu == load_game_menu )
482 process_load_game_menu();
487 if(!game_pause && !Menu::current())
489 frame_ratio *= game_speed;
490 frame_ratio += overlap;
491 while (frame_ratio > 0)
496 overlap = frame_ratio;
498 if (exit_status != NONE)
507 if(debug_mode && debug_fps)
510 /*Draw the current scene to the screen */
511 /*If the machine running the game is too slow
512 skip the drawing of the frame (so the calculations are more precise and
513 the FPS aren't affected).*/
514 /*if( ! fps_fps < 50.0 )
517 jump = true;*/ /*FIXME: Implement this tweak right.*/
520 /* Time stops in pause mode */
521 if(game_pause || Menu::current())
526 /* Set the time of the last update and the time of the current update */
527 last_update_time = update_time;
528 update_time = st_get_ticks();
530 /* Pause till next frame, if the machine running the game is too fast: */
531 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
532 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
533 if(last_update_time >= update_time - 12) {
535 update_time = st_get_ticks();
537 /*if((update_time - last_update_time) < 10)
538 SDL_Delay((11 - (update_time - last_update_time))/2);*/
541 if (time_left.check())
543 /* are we low on time ? */
544 if (time_left.get_left() < TIME_WARNING
545 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
547 set_current_music(HURRYUP_MUSIC);
548 play_current_music();
551 else if(tux->dying == DYING_NOT)
554 /* Calculate frames per second */
558 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
560 if(!fps_timer.check())
562 fps_timer.start(1000);
570 world->get_level()->free_gfx();
571 world->get_level()->cleanup();
572 world->get_level()->free_song();
577 /* Bounce a brick: */
578 void bumpbrick(float x, float y)
580 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
583 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
588 GameSession::drawstatus()
592 sprintf(str, "%d", player_status.score);
593 white_text->draw("SCORE", 0, 0, 1);
594 gold_text->draw(str, 96, 0, 1);
596 if(st_gl_mode == ST_GL_TEST)
598 white_text->draw("Press ESC To Return",0,20,1);
601 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
603 sprintf(str, "%d", time_left.get_left() / 1000 );
604 white_text->draw("TIME", 224, 0, 1);
605 gold_text->draw(str, 304, 0, 1);
608 sprintf(str, "%d", player_status.distros);
609 white_text->draw("DISTROS", screen->h, 0, 1);
610 gold_text->draw(str, 608, 0, 1);
612 white_text->draw("LIVES", screen->h, 20, 1);
616 sprintf(str, "%2.1f", fps_fps);
617 white_text->draw("FPS", screen->h, 40, 1);
618 gold_text->draw(str, screen->h + 60, 40, 1);
621 for(int i= 0; i < player_status.lives; ++i)
623 tux_life->draw(565+(18*i),20);
628 GameSession::drawendscreen()
632 clearscreen(0, 0, 0);
634 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
636 sprintf(str, "SCORE: %d", player_status.score);
637 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
639 sprintf(str, "COINS: %d", player_status.distros);
640 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
645 wait_for_event(event,2000,5000,true);
649 GameSession::drawresultscreen(void)
653 clearscreen(0, 0, 0);
655 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
657 sprintf(str, "SCORE: %d", player_status.score);
658 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
660 sprintf(str, "DISTROS: %d", player_status.distros);
661 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
666 wait_for_event(event,2000,5000,true);
669 std::string slotinfo(int slot)
673 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
675 if (access(slotfile, F_OK) == 0)
676 sprintf(tmp,"Slot %d - Savegame",slot);
678 sprintf(tmp,"Slot %d - Free",slot);