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_), end_sequenze(false),
65 global_frame_counter = 0;
69 frame_timer.init(true);
75 GameSession::restart_level()
82 frame_timer.init(true);
87 { // Tux has lost a life, so we try to respawn him at the nearest reset point
88 old_x_pos = world->get_tux()->base.x;
93 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
95 world = new World(subset);
97 else if (st_gl_mode == ST_GL_DEMO_GAME)
99 world = new World(subset);
103 world = new World(subset, levelnb);
106 // Set Tux to the nearest reset point
109 ResetPoint best_reset_point = { -1, -1 };
110 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
111 i != get_level()->reset_points.end(); ++i)
113 if (i->x < old_x_pos && best_reset_point.x < i->x)
114 best_reset_point = *i;
117 if (best_reset_point.x != -1)
119 world->get_tux()->base.x = best_reset_point.x;
120 world->get_tux()->base.y = best_reset_point.y;
125 if (st_gl_mode != ST_GL_DEMO_GAME)
127 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
131 time_left.init(true);
133 world->play_music(LEVEL_MUSIC);
136 GameSession::~GameSession()
142 GameSession::levelintro(void)
146 clearscreen(0, 0, 0);
148 sprintf(str, "%s", world->get_level()->name.c_str());
149 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
151 sprintf(str, "TUX x %d", player_status.lives);
152 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
154 sprintf(str, "by %s", world->get_level()->author.c_str());
155 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
161 wait_for_event(event,1000,3000,true);
166 GameSession::start_timers()
168 time_left.start(world->get_level()->time_left*1000);
169 st_pause_ticks_init();
170 update_time = st_get_ticks();
174 GameSession::on_escape_press()
179 if(st_gl_mode == ST_GL_TEST)
181 exit_status = LEVEL_ABORT;
183 else if (!Menu::current())
185 Menu::set_current(game_menu);
190 GameSession::process_events()
194 Player& tux = *world->get_tux();
197 tux.input.right = DOWN;
200 if (int(last_x_pos) == int(tux.base.x))
205 last_x_pos = tux.base.x;
209 if(!Menu::current() && !game_pause)
210 st_pause_ticks_stop();
213 while (SDL_PollEvent(&event))
215 /* Check for menu-events, if the menu is shown */
218 Menu::current()->event(event);
219 st_pause_ticks_start();
223 Player& tux = *world->get_tux();
227 case SDL_QUIT: /* Quit event - quit: */
228 st_abort("Received window close", "");
231 case SDL_KEYDOWN: /* A keypress! */
233 SDLKey key = event.key.keysym.sym;
235 if(tux.key_event(key,DOWN))
240 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
248 case SDL_KEYUP: /* A keyrelease! */
250 SDLKey key = event.key.keysym.sym;
252 if(tux.key_event(key, UP))
263 st_pause_ticks_stop();
268 st_pause_ticks_start();
275 tux.size = !tux.size;
278 tux.base.height = 64;
281 tux.base.height = 32;
286 player_status.distros += 50;
294 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
298 --player_status.lives;
302 player_status.score += 1000;
315 case SDL_JOYAXISMOTION:
316 if (event.jaxis.axis == joystick_keymap.x_axis)
318 if (event.jaxis.value < -joystick_keymap.dead_zone)
320 tux.input.left = DOWN;
321 tux.input.right = UP;
323 else if (event.jaxis.value > joystick_keymap.dead_zone)
326 tux.input.right = DOWN;
330 tux.input.left = DOWN;
331 tux.input.right = DOWN;
334 else if (event.jaxis.axis == joystick_keymap.y_axis)
336 if (event.jaxis.value > joystick_keymap.dead_zone)
337 tux.input.down = DOWN;
338 else if (event.jaxis.value < -joystick_keymap.dead_zone)
345 case SDL_JOYBUTTONDOWN:
346 if (event.jbutton.button == joystick_keymap.a_button)
348 else if (event.jbutton.button == joystick_keymap.b_button)
349 tux.input.fire = DOWN;
350 else if (event.jbutton.button == joystick_keymap.start_button)
353 case SDL_JOYBUTTONUP:
354 if (event.jbutton.button == joystick_keymap.a_button)
356 else if (event.jbutton.button == joystick_keymap.b_button)
370 GameSession::check_end_conditions()
372 Player* tux = world->get_tux();
375 if (tux->base.x >= World::current()->get_level()->endpos + 320)
377 exit_status = LEVEL_FINISHED;
379 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequenze)
387 // Check End conditions
390 player_status.lives -= 1;
392 if (player_status.lives < 0)
394 if(st_gl_mode != ST_GL_TEST)
397 exit_status = GAME_OVER;
400 { // Still has lives, so reset Tux to the levelstart
408 GameSession::action(double frame_ratio)
410 check_end_conditions();
412 if (exit_status == NONE)
414 // Update Tux and the World
415 world->action(frame_ratio);
427 int x = screen->h / 20;
428 for(int i = 0; i < x; ++i)
430 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);
432 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
433 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
438 Menu::current()->draw();
439 mouse_cursor->draw();
446 GameSession::process_menu()
448 Menu* menu = Menu::current();
453 if(menu == game_menu)
455 switch (game_menu->check())
458 st_pause_ticks_stop();
461 st_pause_ticks_stop();
462 exit_status = LEVEL_ABORT;
466 else if(menu == options_menu)
468 process_options_menu();
470 else if(menu == load_game_menu )
472 process_load_game_menu();
477 GameSession::ExitStatus
480 Menu::set_current(0);
485 update_time = last_update_time = st_get_ticks();
488 clearscreen(0, 0, 0);
491 // Eat unneeded events
493 while (SDL_PollEvent(&event)) {}
497 float overlap = 0.0f;
498 while (exit_status == NONE)
500 /* Calculate the movement-factor */
501 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
503 if(!frame_timer.check())
505 frame_timer.start(25);
506 ++global_frame_counter;
510 world->get_tux()->input.old_fire = world->get_tux()->input.fire;
515 // Update the world state and all objects in the world
516 // Do that with a constante time-delta so that the game will run
517 // determistic and not different on different machines
518 if(!game_pause && !Menu::current())
520 frame_ratio *= game_speed;
521 frame_ratio += overlap;
522 while (frame_ratio > 0)
531 overlap = frame_ratio;
541 /* Time stops in pause mode */
542 if(game_pause || Menu::current())
547 /* Set the time of the last update and the time of the current update */
548 last_update_time = update_time;
549 update_time = st_get_ticks();
551 /* Pause till next frame, if the machine running the game is too fast: */
552 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
553 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
554 if(last_update_time >= update_time - 12)
557 update_time = st_get_ticks();
561 if (!time_left.check() && world->get_tux()->dying == DYING_NOT)
562 world->get_tux()->kill(Player::KILL);
565 if(world->get_tux()->invincible_timer.check())
567 if(world->get_music_type() != HERRING_MUSIC)
568 world->play_music(HERRING_MUSIC);
570 /* are we low on time ? */
571 else if (time_left.get_left() < TIME_WARNING
572 && (world->get_music_type() == LEVEL_MUSIC))
574 world->play_music(HURRYUP_MUSIC);
576 /* or just normal music? */
577 else if(world->get_music_type() != LEVEL_MUSIC)
579 world->play_music(LEVEL_MUSIC);
582 /* Calculate frames per second */
586 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
588 if(!fps_timer.check())
590 fps_timer.start(1000);
602 /* Bounce a brick: */
603 void bumpbrick(float x, float y)
605 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
608 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
613 GameSession::drawstatus()
617 sprintf(str, "%d", player_status.score);
618 white_text->draw("SCORE", 0, 0, 1);
619 gold_text->draw(str, 96, 0, 1);
621 if(st_gl_mode == ST_GL_TEST)
623 white_text->draw("Press ESC To Return",0,20,1);
626 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
628 sprintf(str, "%d", time_left.get_left() / 1000 );
629 white_text->draw("TIME", 224, 0, 1);
630 gold_text->draw(str, 304, 0, 1);
633 sprintf(str, "%d", player_status.distros);
634 white_text->draw("DISTROS", screen->h, 0, 1);
635 gold_text->draw(str, 608, 0, 1);
637 white_text->draw("LIVES", screen->h, 20, 1);
641 sprintf(str, "%2.1f", fps_fps);
642 white_text->draw("FPS", screen->h, 40, 1);
643 gold_text->draw(str, screen->h + 60, 40, 1);
646 for(int i= 0; i < player_status.lives; ++i)
648 tux_life->draw(565+(18*i),20);
653 GameSession::drawendscreen()
657 clearscreen(0, 0, 0);
659 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
661 sprintf(str, "SCORE: %d", player_status.score);
662 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
664 sprintf(str, "COINS: %d", player_status.distros);
665 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
670 wait_for_event(event,2000,5000,true);
674 GameSession::drawresultscreen(void)
678 clearscreen(0, 0, 0);
680 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
682 sprintf(str, "SCORE: %d", player_status.score);
683 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
685 sprintf(str, "DISTROS: %d", player_status.distros);
686 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
691 wait_for_event(event,2000,5000,true);
694 std::string slotinfo(int slot)
698 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
700 if (access(slotfile, F_OK) == 0)
701 sprintf(tmp,"Slot %d - Savegame",slot);
703 sprintf(tmp,"Slot %d - Free",slot);