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_)
68 GameSession::restart_level()
75 frame_timer.init(true);
80 { // Tux has lost a life, so we try to respawn him at the nearest reset point
81 old_x_pos = world->get_tux()->base.x;
86 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
88 world = new World(subset);
90 else if (st_gl_mode == ST_GL_DEMO_GAME)
92 world = new World(subset);
96 world = new World(subset, levelnb);
99 // Set Tux to the nearest reset point
102 ResetPoint best_reset_point = { -1, -1 };
103 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
104 i != get_level()->reset_points.end(); ++i)
106 if (i->x < old_x_pos && best_reset_point.x < i->x)
107 best_reset_point = *i;
110 if (best_reset_point.x != -1)
112 world->get_tux()->base.x = best_reset_point.x;
113 world->get_tux()->base.y = best_reset_point.y;
118 if (st_gl_mode != ST_GL_DEMO_GAME)
120 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
124 time_left.init(true);
126 world->play_music(LEVEL_MUSIC);
129 GameSession::~GameSession()
135 GameSession::levelintro(void)
139 clearscreen(0, 0, 0);
141 sprintf(str, "%s", world->get_level()->name.c_str());
142 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
144 sprintf(str, "TUX x %d", player_status.lives);
145 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
147 sprintf(str, "by %s", world->get_level()->author.c_str());
148 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
154 wait_for_event(event,1000,3000,true);
159 GameSession::start_timers()
161 time_left.start(world->get_level()->time_left*1000);
162 st_pause_ticks_init();
163 update_time = st_get_ticks();
167 GameSession::on_escape_press()
169 if(st_gl_mode == ST_GL_TEST)
171 exit_status = LEVEL_ABORT;
173 else if (!Menu::current())
175 Menu::set_current(game_menu);
180 GameSession::process_events()
184 Player& tux = *world->get_tux();
187 tux.input.right = DOWN;
190 if (int(last_x_pos) == int(tux.base.x))
195 last_x_pos = tux.base.x;
200 while (SDL_PollEvent(&event))
202 /* Check for menu-events, if the menu is shown */
205 Menu::current()->event(event);
206 st_pause_ticks_start();
210 Player& tux = *world->get_tux();
212 st_pause_ticks_stop();
216 case SDL_QUIT: /* Quit event - quit: */
217 st_abort("Received window close", "");
220 case SDL_KEYDOWN: /* A keypress! */
222 SDLKey key = event.key.keysym.sym;
224 if(tux.key_event(key,DOWN))
229 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
237 case SDL_KEYUP: /* A keyrelease! */
239 SDLKey key = event.key.keysym.sym;
241 if(tux.key_event(key, UP))
252 st_pause_ticks_stop();
257 st_pause_ticks_start();
264 tux.size = !tux.size;
267 tux.base.height = 64;
270 tux.base.height = 32;
275 player_status.distros += 50;
283 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
287 --player_status.lives;
291 player_status.score += 1000;
304 case SDL_JOYAXISMOTION:
305 if (event.jaxis.axis == joystick_keymap.x_axis)
307 if (event.jaxis.value < -joystick_keymap.dead_zone)
309 tux.input.left = DOWN;
310 tux.input.right = UP;
312 else if (event.jaxis.value > joystick_keymap.dead_zone)
315 tux.input.right = DOWN;
319 tux.input.left = DOWN;
320 tux.input.right = DOWN;
323 else if (event.jaxis.axis == joystick_keymap.y_axis)
325 if (event.jaxis.value > joystick_keymap.dead_zone)
326 tux.input.down = DOWN;
327 else if (event.jaxis.value < -joystick_keymap.dead_zone)
334 case SDL_JOYBUTTONDOWN:
335 if (event.jbutton.button == joystick_keymap.a_button)
337 else if (event.jbutton.button == joystick_keymap.b_button)
338 tux.input.fire = DOWN;
339 else if (event.jbutton.button == joystick_keymap.start_button)
342 case SDL_JOYBUTTONUP:
343 if (event.jbutton.button == joystick_keymap.a_button)
345 else if (event.jbutton.button == joystick_keymap.b_button)
359 GameSession::check_end_conditions()
361 Player* tux = world->get_tux();
364 if (tux->base.x >= World::current()->get_level()->endpos + 320)
366 exit_status = LEVEL_FINISHED;
368 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequenze)
376 // Check End conditions
379 player_status.lives -= 1;
381 if (player_status.lives < 0)
383 if(st_gl_mode != ST_GL_TEST)
386 exit_status = GAME_OVER;
389 { // Still has lives, so reset Tux to the levelstart
397 GameSession::action(double frame_ratio)
399 check_end_conditions();
401 if (exit_status == NONE)
403 // Update Tux and the World
404 world->action(frame_ratio);
416 int x = screen->h / 20;
417 for(int i = 0; i < x; ++i)
419 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);
421 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
422 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
427 Menu::current()->draw();
428 mouse_cursor->draw();
435 GameSession::process_menu()
437 Menu* menu = Menu::current();
442 if(menu == game_menu)
444 switch (game_menu->check())
447 st_pause_ticks_stop();
450 st_pause_ticks_stop();
451 exit_status = LEVEL_ABORT;
455 else if(menu == options_menu)
457 process_options_menu();
459 else if(menu == load_game_menu )
461 process_load_game_menu();
466 GameSession::ExitStatus
469 Menu::set_current(0);
470 Player* tux = world->get_tux();
475 global_frame_counter = 0;
478 fps_timer.init(true);
479 frame_timer.init(true);
481 last_update_time = st_get_ticks();
485 clearscreen(0, 0, 0);
488 // Eat unneeded events
490 while (SDL_PollEvent(&event)) {}
494 float overlap = 0.0f;
495 while (exit_status == NONE)
497 /* Calculate the movement-factor */
498 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
500 if(!frame_timer.check())
502 frame_timer.start(25);
503 ++global_frame_counter;
507 tux->input.old_fire = tux->input.fire;
512 // Update the world state and all objects in the world
513 // Do that with a constante time-delta so that the game will run
514 // determistic and not different on different machines
515 if(!game_pause && !Menu::current())
517 frame_ratio *= game_speed;
518 frame_ratio += overlap;
519 while (frame_ratio > 0)
528 overlap = frame_ratio;
538 /* Time stops in pause mode */
539 if(game_pause || Menu::current())
544 /* Set the time of the last update and the time of the current update */
545 last_update_time = update_time;
546 update_time = st_get_ticks();
548 /* Pause till next frame, if the machine running the game is too fast: */
549 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
550 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
551 if(last_update_time >= update_time - 12)
554 update_time = st_get_ticks();
558 if (!time_left.check() && tux->dying == DYING_NOT)
562 if(tux->invincible_timer.check())
564 if(world->get_music_type() != HERRING_MUSIC)
565 world->play_music(HERRING_MUSIC);
567 /* are we low on time ? */
568 else if (time_left.get_left() < TIME_WARNING
569 && (world->get_music_type() == LEVEL_MUSIC))
571 world->play_music(HURRYUP_MUSIC);
573 /* or just normal music? */
574 else if(world->get_music_type() != LEVEL_MUSIC)
576 world->play_music(LEVEL_MUSIC);
579 /* Calculate frames per second */
583 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
585 if(!fps_timer.check())
587 fps_timer.start(1000);
599 /* Bounce a brick: */
600 void bumpbrick(float x, float y)
602 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
605 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
610 GameSession::drawstatus()
614 sprintf(str, "%d", player_status.score);
615 white_text->draw("SCORE", 0, 0, 1);
616 gold_text->draw(str, 96, 0, 1);
618 if(st_gl_mode == ST_GL_TEST)
620 white_text->draw("Press ESC To Return",0,20,1);
623 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
625 sprintf(str, "%d", time_left.get_left() / 1000 );
626 white_text->draw("TIME", 224, 0, 1);
627 gold_text->draw(str, 304, 0, 1);
630 sprintf(str, "%d", player_status.distros);
631 white_text->draw("DISTROS", screen->h, 0, 1);
632 gold_text->draw(str, 608, 0, 1);
634 white_text->draw("LIVES", screen->h, 20, 1);
638 sprintf(str, "%2.1f", fps_fps);
639 white_text->draw("FPS", screen->h, 40, 1);
640 gold_text->draw(str, screen->h + 60, 40, 1);
643 for(int i= 0; i < player_status.lives; ++i)
645 tux_life->draw(565+(18*i),20);
650 GameSession::drawendscreen()
654 clearscreen(0, 0, 0);
656 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
658 sprintf(str, "SCORE: %d", player_status.score);
659 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
661 sprintf(str, "COINS: %d", player_status.distros);
662 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
667 wait_for_event(event,2000,5000,true);
671 GameSession::drawresultscreen(void)
675 clearscreen(0, 0, 0);
677 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
679 sprintf(str, "SCORE: %d", player_status.score);
680 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
682 sprintf(str, "DISTROS: %d", player_status.distros);
683 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
688 wait_for_event(event,2000,5000,true);
691 std::string slotinfo(int slot)
695 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
697 if (access(slotfile, F_OK) == 0)
698 sprintf(tmp,"Slot %d - Savegame",slot);
700 sprintf(tmp,"Slot %d - Free",slot);