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"
56 #include "music_manager.h"
58 GameSession* GameSession::current_ = 0;
60 GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
61 : world(0), st_gl_mode(mode), levelnb(levelnb_), end_sequenze(false),
66 global_frame_counter = 0;
70 frame_timer.init(true);
76 GameSession::restart_level()
83 frame_timer.init(true);
88 { // Tux has lost a life, so we try to respawn him at the nearest reset point
89 old_x_pos = world->get_tux()->base.x;
94 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
96 world = new World(subset);
98 else if (st_gl_mode == ST_GL_DEMO_GAME)
100 world = new World(subset);
104 world = new World(subset, levelnb);
107 // Set Tux to the nearest reset point
110 ResetPoint best_reset_point = { -1, -1 };
111 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
112 i != get_level()->reset_points.end(); ++i)
114 if (i->x < old_x_pos && best_reset_point.x < i->x)
115 best_reset_point = *i;
118 if (best_reset_point.x != -1)
120 world->get_tux()->base.x = best_reset_point.x;
121 world->get_tux()->base.y = best_reset_point.y;
126 if (st_gl_mode != ST_GL_DEMO_GAME)
128 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
132 time_left.init(true);
134 world->play_music(LEVEL_MUSIC);
137 GameSession::~GameSession()
143 GameSession::levelintro(void)
145 music_manager->halt_music();
149 clearscreen(0, 0, 0);
151 sprintf(str, "%s", world->get_level()->name.c_str());
152 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
154 sprintf(str, "TUX x %d", player_status.lives);
155 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
157 sprintf(str, "by %s", world->get_level()->author.c_str());
158 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
164 wait_for_event(event,1000,3000,true);
169 GameSession::start_timers()
171 time_left.start(world->get_level()->time_left*1000);
172 st_pause_ticks_init();
173 update_time = st_get_ticks();
177 GameSession::on_escape_press()
182 if(st_gl_mode == ST_GL_TEST)
184 exit_status = LEVEL_ABORT;
186 else if (!Menu::current())
188 Menu::set_current(game_menu);
193 GameSession::process_events()
197 Player& tux = *world->get_tux();
200 tux.input.right = DOWN;
203 if (int(last_x_pos) == int(tux.base.x))
208 last_x_pos = tux.base.x;
212 if(!Menu::current() && !game_pause)
213 st_pause_ticks_stop();
216 while (SDL_PollEvent(&event))
218 /* Check for menu-events, if the menu is shown */
221 Menu::current()->event(event);
222 st_pause_ticks_start();
226 Player& tux = *world->get_tux();
230 case SDL_QUIT: /* Quit event - quit: */
231 st_abort("Received window close", "");
234 case SDL_KEYDOWN: /* A keypress! */
236 SDLKey key = event.key.keysym.sym;
238 if(tux.key_event(key,DOWN))
243 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
251 case SDL_KEYUP: /* A keyrelease! */
253 SDLKey key = event.key.keysym.sym;
255 if(tux.key_event(key, UP))
266 st_pause_ticks_stop();
271 st_pause_ticks_start();
278 tux.size = !tux.size;
281 tux.base.height = 64;
284 tux.base.height = 32;
289 player_status.distros += 50;
297 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
301 --player_status.lives;
305 player_status.score += 1000;
318 case SDL_JOYAXISMOTION:
319 if (event.jaxis.axis == joystick_keymap.x_axis)
321 if (event.jaxis.value < -joystick_keymap.dead_zone)
323 tux.input.left = DOWN;
324 tux.input.right = UP;
326 else if (event.jaxis.value > joystick_keymap.dead_zone)
329 tux.input.right = DOWN;
333 tux.input.left = DOWN;
334 tux.input.right = DOWN;
337 else if (event.jaxis.axis == joystick_keymap.y_axis)
339 if (event.jaxis.value > joystick_keymap.dead_zone)
340 tux.input.down = DOWN;
341 else if (event.jaxis.value < -joystick_keymap.dead_zone)
348 case SDL_JOYBUTTONDOWN:
349 if (event.jbutton.button == joystick_keymap.a_button)
351 else if (event.jbutton.button == joystick_keymap.b_button)
352 tux.input.fire = DOWN;
353 else if (event.jbutton.button == joystick_keymap.start_button)
356 case SDL_JOYBUTTONUP:
357 if (event.jbutton.button == joystick_keymap.a_button)
359 else if (event.jbutton.button == joystick_keymap.b_button)
373 GameSession::check_end_conditions()
375 Player* tux = world->get_tux();
378 if (tux->base.x >= World::current()->get_level()->endpos + 320)
380 exit_status = LEVEL_FINISHED;
382 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequenze)
386 music_manager->halt_music();
390 // Check End conditions
393 player_status.lives -= 1;
395 if (player_status.lives < 0)
397 if(st_gl_mode != ST_GL_TEST)
400 exit_status = GAME_OVER;
403 { // Still has lives, so reset Tux to the levelstart
411 GameSession::action(double frame_ratio)
413 check_end_conditions();
415 if (exit_status == NONE)
417 // Update Tux and the World
418 world->action(frame_ratio);
430 int x = screen->h / 20;
431 for(int i = 0; i < x; ++i)
433 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);
435 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
436 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
441 Menu::current()->draw();
442 mouse_cursor->draw();
449 GameSession::process_menu()
451 Menu* menu = Menu::current();
456 if(menu == game_menu)
458 switch (game_menu->check())
461 st_pause_ticks_stop();
463 case MNID_ABORTLEVEL:
464 st_pause_ticks_stop();
465 exit_status = LEVEL_ABORT;
469 else if(menu == options_menu)
471 process_options_menu();
473 else if(menu == load_game_menu )
475 process_load_game_menu();
480 GameSession::ExitStatus
483 Menu::set_current(0);
488 update_time = last_update_time = st_get_ticks();
491 clearscreen(0, 0, 0);
494 // Eat unneeded events
496 while (SDL_PollEvent(&event)) {}
500 float overlap = 0.0f;
501 while (exit_status == NONE)
503 /* Calculate the movement-factor */
504 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
506 if(!frame_timer.check())
508 frame_timer.start(25);
509 ++global_frame_counter;
513 world->get_tux()->input.old_fire = world->get_tux()->input.fire;
518 // Update the world state and all objects in the world
519 // Do that with a constante time-delta so that the game will run
520 // determistic and not different on different machines
521 if(!game_pause && !Menu::current())
523 frame_ratio *= game_speed;
524 frame_ratio += overlap;
525 while (frame_ratio > 0)
534 overlap = frame_ratio;
544 /* Time stops in pause mode */
545 if(game_pause || Menu::current())
550 /* Set the time of the last update and the time of the current update */
551 last_update_time = update_time;
552 update_time = st_get_ticks();
554 /* Pause till next frame, if the machine running the game is too fast: */
555 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
556 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
557 if(last_update_time >= update_time - 12)
560 update_time = st_get_ticks();
564 if (!time_left.check() && world->get_tux()->dying == DYING_NOT)
565 world->get_tux()->kill(Player::KILL);
568 if(world->get_tux()->invincible_timer.check())
570 if(world->get_music_type() != HERRING_MUSIC)
571 world->play_music(HERRING_MUSIC);
573 /* are we low on time ? */
574 else if (time_left.get_left() < TIME_WARNING
575 && (world->get_music_type() == LEVEL_MUSIC))
577 world->play_music(HURRYUP_MUSIC);
579 /* or just normal music? */
580 else if(world->get_music_type() != LEVEL_MUSIC)
582 world->play_music(LEVEL_MUSIC);
585 /* Calculate frames per second */
589 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
591 if(!fps_timer.check())
593 fps_timer.start(1000);
605 /* Bounce a brick: */
606 void bumpbrick(float x, float y)
608 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
611 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
616 GameSession::drawstatus()
620 sprintf(str, "%d", player_status.score);
621 white_text->draw("SCORE", 0, 0, 1);
622 gold_text->draw(str, 96, 0, 1);
624 if(st_gl_mode == ST_GL_TEST)
626 white_text->draw("Press ESC To Return",0,20,1);
629 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
631 sprintf(str, "%d", time_left.get_left() / 1000 );
632 white_text->draw("TIME", 224, 0, 1);
633 gold_text->draw(str, 304, 0, 1);
636 sprintf(str, "%d", player_status.distros);
637 white_text->draw("DISTROS", screen->h, 0, 1);
638 gold_text->draw(str, 608, 0, 1);
640 white_text->draw("LIVES", screen->h, 20, 1);
644 sprintf(str, "%2.1f", fps_fps);
645 white_text->draw("FPS", screen->h, 40, 1);
646 gold_text->draw(str, screen->h + 60, 40, 1);
649 for(int i= 0; i < player_status.lives; ++i)
651 tux_life->draw(565+(18*i),20);
656 GameSession::drawendscreen()
660 clearscreen(0, 0, 0);
662 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
664 sprintf(str, "SCORE: %d", player_status.score);
665 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
667 sprintf(str, "COINS: %d", player_status.distros);
668 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
673 wait_for_event(event,2000,5000,true);
677 GameSession::drawresultscreen(void)
681 clearscreen(0, 0, 0);
683 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
685 sprintf(str, "SCORE: %d", player_status.score);
686 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
688 sprintf(str, "DISTROS: %d", player_status.distros);
689 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
694 wait_for_event(event,2000,5000,true);
697 std::string slotinfo(int slot)
701 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
703 if (access(slotfile, F_OK) == 0)
704 sprintf(tmp,"Slot %d - Savegame",slot);
706 sprintf(tmp,"Slot %d - Free",slot);