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;
214 while (SDL_PollEvent(&event))
216 /* Check for menu-events, if the menu is shown */
219 Menu::current()->event(event);
220 st_pause_ticks_start();
225 case SDL_QUIT: /* Quit event - quit: */
226 st_abort("Received window close", "");
229 case SDL_KEYDOWN: /* A keypress! */
231 SDLKey key = event.key.keysym.sym;
235 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
243 case SDL_JOYBUTTONDOWN:
244 if (event.jbutton.button == joystick_keymap.start_button)
252 if(!Menu::current() && !game_pause)
253 st_pause_ticks_stop();
256 while (SDL_PollEvent(&event))
258 /* Check for menu-events, if the menu is shown */
261 Menu::current()->event(event);
262 st_pause_ticks_start();
266 Player& tux = *world->get_tux();
270 case SDL_QUIT: /* Quit event - quit: */
271 st_abort("Received window close", "");
274 case SDL_KEYDOWN: /* A keypress! */
276 SDLKey key = event.key.keysym.sym;
278 if(tux.key_event(key,DOWN))
283 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
291 case SDL_KEYUP: /* A keyrelease! */
293 SDLKey key = event.key.keysym.sym;
295 if(tux.key_event(key, UP))
306 st_pause_ticks_stop();
311 st_pause_ticks_start();
318 tux.size = !tux.size;
321 tux.base.height = 64;
324 tux.base.height = 32;
329 player_status.distros += 50;
337 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
341 --player_status.lives;
345 player_status.score += 1000;
358 case SDL_JOYAXISMOTION:
359 if (event.jaxis.axis == joystick_keymap.x_axis)
361 if (event.jaxis.value < -joystick_keymap.dead_zone)
363 tux.input.left = DOWN;
364 tux.input.right = UP;
366 else if (event.jaxis.value > joystick_keymap.dead_zone)
369 tux.input.right = DOWN;
373 tux.input.left = DOWN;
374 tux.input.right = DOWN;
377 else if (event.jaxis.axis == joystick_keymap.y_axis)
379 if (event.jaxis.value > joystick_keymap.dead_zone)
380 tux.input.down = DOWN;
381 else if (event.jaxis.value < -joystick_keymap.dead_zone)
388 case SDL_JOYBUTTONDOWN:
389 if (event.jbutton.button == joystick_keymap.a_button)
391 else if (event.jbutton.button == joystick_keymap.b_button)
392 tux.input.fire = DOWN;
393 else if (event.jbutton.button == joystick_keymap.start_button)
396 case SDL_JOYBUTTONUP:
397 if (event.jbutton.button == joystick_keymap.a_button)
399 else if (event.jbutton.button == joystick_keymap.b_button)
413 GameSession::check_end_conditions()
415 Player* tux = world->get_tux();
418 if (tux->base.x >= World::current()->get_level()->endpos + 32 * (get_level()->use_endsequence ? 22 : 10))
420 exit_status = LEVEL_FINISHED;
422 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequence)
426 music_manager->halt_music();
430 // Check End conditions
433 player_status.lives -= 1;
435 if (player_status.lives < 0)
437 if(st_gl_mode != ST_GL_TEST)
440 exit_status = GAME_OVER;
443 { // Still has lives, so reset Tux to the levelstart
451 GameSession::action(double frame_ratio)
453 check_end_conditions();
455 if (exit_status == NONE)
457 // Update Tux and the World
458 world->action(frame_ratio);
470 int x = screen->h / 20;
471 for(int i = 0; i < x; ++i)
473 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);
475 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
476 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
481 Menu::current()->draw();
482 mouse_cursor->draw();
489 GameSession::process_menu()
491 Menu* menu = Menu::current();
496 if(menu == game_menu)
498 switch (game_menu->check())
501 st_pause_ticks_stop();
503 case MNID_ABORTLEVEL:
504 st_pause_ticks_stop();
505 exit_status = LEVEL_ABORT;
509 else if(menu == options_menu)
511 process_options_menu();
513 else if(menu == load_game_menu )
515 process_load_game_menu();
520 GameSession::ExitStatus
523 Menu::set_current(0);
528 update_time = last_update_time = st_get_ticks();
531 clearscreen(0, 0, 0);
534 // Eat unneeded events
536 while (SDL_PollEvent(&event)) {}
540 float overlap = 0.0f;
541 while (exit_status == NONE)
543 /* Calculate the movement-factor */
544 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
546 if(!frame_timer.check())
548 frame_timer.start(25);
549 ++global_frame_counter;
553 world->get_tux()->input.old_fire = world->get_tux()->input.fire;
558 // Update the world state and all objects in the world
559 // Do that with a constante time-delta so that the game will run
560 // determistic and not different on different machines
561 if(!game_pause && !Menu::current())
563 frame_ratio *= game_speed;
564 frame_ratio += overlap;
565 while (frame_ratio > 0)
574 overlap = frame_ratio;
584 /* Time stops in pause mode */
585 if(game_pause || Menu::current())
590 /* Set the time of the last update and the time of the current update */
591 last_update_time = update_time;
592 update_time = st_get_ticks();
594 /* Pause till next frame, if the machine running the game is too fast: */
595 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
596 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
597 if(last_update_time >= update_time - 12)
600 update_time = st_get_ticks();
604 if (!time_left.check() && world->get_tux()->dying == DYING_NOT)
605 world->get_tux()->kill(Player::KILL);
608 if(world->get_tux()->invincible_timer.check())
610 if(world->get_music_type() != HERRING_MUSIC)
611 world->play_music(HERRING_MUSIC);
613 /* are we low on time ? */
614 else if (time_left.get_left() < TIME_WARNING
615 && (world->get_music_type() == LEVEL_MUSIC))
617 world->play_music(HURRYUP_MUSIC);
619 /* or just normal music? */
620 else if(world->get_music_type() != LEVEL_MUSIC)
622 world->play_music(LEVEL_MUSIC);
625 /* Calculate frames per second */
629 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
631 if(!fps_timer.check())
633 fps_timer.start(1000);
642 /* Bounce a brick: */
643 void bumpbrick(float x, float y)
645 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
648 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
653 GameSession::drawstatus()
657 sprintf(str, "%d", player_status.score);
658 white_text->draw("SCORE", 0, 0, 1);
659 gold_text->draw(str, 96, 0, 1);
661 if(st_gl_mode == ST_GL_TEST)
663 white_text->draw("Press ESC To Return",0,20,1);
666 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
668 sprintf(str, "%d", time_left.get_left() / 1000 );
669 white_text->draw("TIME", 224, 0, 1);
670 gold_text->draw(str, 304, 0, 1);
673 sprintf(str, "%d", player_status.distros);
674 white_text->draw("COINS", screen->h, 0, 1);
675 gold_text->draw(str, 608, 0, 1);
677 white_text->draw("LIVES", screen->h, 20, 1);
681 sprintf(str, "%2.1f", fps_fps);
682 white_text->draw("FPS", screen->h, 40, 1);
683 gold_text->draw(str, screen->h + 60, 40, 1);
686 for(int i= 0; i < player_status.lives; ++i)
688 tux_life->draw(565+(18*i),20);
693 GameSession::drawendscreen()
697 if (get_level()->img_bkgd)
698 get_level()->img_bkgd->draw(0, 0);
700 drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom);
702 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
704 sprintf(str, "SCORE: %d", player_status.score);
705 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
707 sprintf(str, "COINS: %d", player_status.distros);
708 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
713 wait_for_event(event,2000,5000,true);
717 GameSession::drawresultscreen(void)
721 if (get_level()->img_bkgd)
722 get_level()->img_bkgd->draw(0, 0);
724 drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom);
726 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
728 sprintf(str, "SCORE: %d", player_status.score);
729 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
731 sprintf(str, "COINS: %d", player_status.distros);
732 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
737 wait_for_event(event,2000,5000,true);
740 std::string slotinfo(int slot)
744 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
746 if (access(slotfile, F_OK) == 0)
747 sprintf(tmp,"Slot %d - Savegame",slot);
749 sprintf(tmp,"Slot %d - Free",slot);