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_sequence(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 if (get_level()->img_bkgd)
150 get_level()->img_bkgd->draw(0, 0);
152 drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom);
154 sprintf(str, "%s", world->get_level()->name.c_str());
155 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
157 sprintf(str, "TUX x %d", player_status.lives);
158 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
160 sprintf(str, "by %s", world->get_level()->author.c_str());
161 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
167 wait_for_event(event,1000,3000,true);
172 GameSession::start_timers()
174 time_left.start(world->get_level()->time_left*1000);
175 st_pause_ticks_init();
176 update_time = st_get_ticks();
180 GameSession::on_escape_press()
185 if(st_gl_mode == ST_GL_TEST)
187 exit_status = LEVEL_ABORT;
189 else if (!Menu::current())
191 Menu::set_current(game_menu);
196 GameSession::process_events()
200 Player& tux = *world->get_tux();
203 tux.input.right = DOWN;
206 if (int(last_x_pos) == int(tux.base.x))
211 last_x_pos = tux.base.x;
215 if(!Menu::current() && !game_pause)
216 st_pause_ticks_stop();
219 while (SDL_PollEvent(&event))
221 /* Check for menu-events, if the menu is shown */
224 Menu::current()->event(event);
225 st_pause_ticks_start();
229 Player& tux = *world->get_tux();
233 case SDL_QUIT: /* Quit event - quit: */
234 st_abort("Received window close", "");
237 case SDL_KEYDOWN: /* A keypress! */
239 SDLKey key = event.key.keysym.sym;
241 if(tux.key_event(key,DOWN))
246 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
254 case SDL_KEYUP: /* A keyrelease! */
256 SDLKey key = event.key.keysym.sym;
258 if(tux.key_event(key, UP))
269 st_pause_ticks_stop();
274 st_pause_ticks_start();
281 tux.size = !tux.size;
284 tux.base.height = 64;
287 tux.base.height = 32;
292 player_status.distros += 50;
300 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
304 --player_status.lives;
308 player_status.score += 1000;
321 case SDL_JOYAXISMOTION:
322 if (event.jaxis.axis == joystick_keymap.x_axis)
324 if (event.jaxis.value < -joystick_keymap.dead_zone)
326 tux.input.left = DOWN;
327 tux.input.right = UP;
329 else if (event.jaxis.value > joystick_keymap.dead_zone)
332 tux.input.right = DOWN;
336 tux.input.left = DOWN;
337 tux.input.right = DOWN;
340 else if (event.jaxis.axis == joystick_keymap.y_axis)
342 if (event.jaxis.value > joystick_keymap.dead_zone)
343 tux.input.down = DOWN;
344 else if (event.jaxis.value < -joystick_keymap.dead_zone)
351 case SDL_JOYBUTTONDOWN:
352 if (event.jbutton.button == joystick_keymap.a_button)
354 else if (event.jbutton.button == joystick_keymap.b_button)
355 tux.input.fire = DOWN;
356 else if (event.jbutton.button == joystick_keymap.start_button)
359 case SDL_JOYBUTTONUP:
360 if (event.jbutton.button == joystick_keymap.a_button)
362 else if (event.jbutton.button == joystick_keymap.b_button)
376 GameSession::check_end_conditions()
378 Player* tux = world->get_tux();
381 if (tux->base.x >= World::current()->get_level()->endpos + 32 * (get_level()->use_endsequence ? 22 : 10))
383 exit_status = LEVEL_FINISHED;
385 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequence)
389 music_manager->halt_music();
393 // Check End conditions
396 player_status.lives -= 1;
398 if (player_status.lives < 0)
400 if(st_gl_mode != ST_GL_TEST)
403 exit_status = GAME_OVER;
406 { // Still has lives, so reset Tux to the levelstart
414 GameSession::action(double frame_ratio)
416 check_end_conditions();
418 if (exit_status == NONE)
420 // Update Tux and the World
421 world->action(frame_ratio);
433 int x = screen->h / 20;
434 for(int i = 0; i < x; ++i)
436 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);
438 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
439 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
444 Menu::current()->draw();
445 mouse_cursor->draw();
452 GameSession::process_menu()
454 Menu* menu = Menu::current();
459 if(menu == game_menu)
461 switch (game_menu->check())
464 st_pause_ticks_stop();
466 case MNID_ABORTLEVEL:
467 st_pause_ticks_stop();
468 exit_status = LEVEL_ABORT;
472 else if(menu == options_menu)
474 process_options_menu();
476 else if(menu == load_game_menu )
478 process_load_game_menu();
483 GameSession::ExitStatus
486 Menu::set_current(0);
491 update_time = last_update_time = st_get_ticks();
494 clearscreen(0, 0, 0);
497 // Eat unneeded events
499 while (SDL_PollEvent(&event)) {}
503 float overlap = 0.0f;
504 while (exit_status == NONE)
506 /* Calculate the movement-factor */
507 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
509 if(!frame_timer.check())
511 frame_timer.start(25);
512 ++global_frame_counter;
516 world->get_tux()->input.old_fire = world->get_tux()->input.fire;
521 // Update the world state and all objects in the world
522 // Do that with a constante time-delta so that the game will run
523 // determistic and not different on different machines
524 if(!game_pause && !Menu::current())
526 frame_ratio *= game_speed;
527 frame_ratio += overlap;
528 while (frame_ratio > 0)
537 overlap = frame_ratio;
547 /* Time stops in pause mode */
548 if(game_pause || Menu::current())
553 /* Set the time of the last update and the time of the current update */
554 last_update_time = update_time;
555 update_time = st_get_ticks();
557 /* Pause till next frame, if the machine running the game is too fast: */
558 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
559 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
560 if(last_update_time >= update_time - 12)
563 update_time = st_get_ticks();
567 if (!time_left.check() && world->get_tux()->dying == DYING_NOT)
568 world->get_tux()->kill(Player::KILL);
571 if(world->get_tux()->invincible_timer.check())
573 if(world->get_music_type() != HERRING_MUSIC)
574 world->play_music(HERRING_MUSIC);
576 /* are we low on time ? */
577 else if (time_left.get_left() < TIME_WARNING
578 && (world->get_music_type() == LEVEL_MUSIC))
580 world->play_music(HURRYUP_MUSIC);
582 /* or just normal music? */
583 else if(world->get_music_type() != LEVEL_MUSIC)
585 world->play_music(LEVEL_MUSIC);
588 /* Calculate frames per second */
592 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
594 if(!fps_timer.check())
596 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("COINS", 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 if (get_level()->img_bkgd)
661 get_level()->img_bkgd->draw(0, 0);
663 drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom);
665 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
667 sprintf(str, "SCORE: %d", player_status.score);
668 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
670 sprintf(str, "COINS: %d", player_status.distros);
671 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
676 wait_for_event(event,2000,5000,true);
680 GameSession::drawresultscreen(void)
684 if (get_level()->img_bkgd)
685 get_level()->img_bkgd->draw(0, 0);
687 drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom);
689 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
691 sprintf(str, "SCORE: %d", player_status.score);
692 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
694 sprintf(str, "COINS: %d", player_status.distros);
695 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
700 wait_for_event(event,2000,5000,true);
703 std::string slotinfo(int slot)
707 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
709 if (access(slotfile, F_OK) == 0)
710 sprintf(tmp,"Slot %d - Savegame",slot);
712 sprintf(tmp,"Slot %d - Free",slot);