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);
128 GameSession::~GameSession()
134 GameSession::levelintro(void)
138 clearscreen(0, 0, 0);
140 sprintf(str, "%s", world->get_level()->name.c_str());
141 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
143 sprintf(str, "TUX x %d", player_status.lives);
144 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
146 sprintf(str, "by %s", world->get_level()->author.c_str());
147 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
153 wait_for_event(event,1000,3000,true);
158 GameSession::start_timers()
160 time_left.start(world->get_level()->time_left*1000);
161 st_pause_ticks_init();
162 update_time = st_get_ticks();
166 GameSession::on_escape_press()
168 if(st_gl_mode == ST_GL_TEST)
170 exit_status = LEVEL_ABORT;
172 else if (!Menu::current())
174 Menu::set_current(game_menu);
179 GameSession::process_events()
183 Player& tux = *world->get_tux();
186 tux.input.right = DOWN;
189 if (int(last_x_pos) == int(tux.base.x))
194 last_x_pos = tux.base.x;
199 while (SDL_PollEvent(&event))
201 /* Check for menu-events, if the menu is shown */
204 Menu::current()->event(event);
205 st_pause_ticks_start();
209 Player& tux = *world->get_tux();
211 st_pause_ticks_stop();
215 case SDL_QUIT: /* Quit event - quit: */
216 st_abort("Received window close", "");
219 case SDL_KEYDOWN: /* A keypress! */
221 SDLKey key = event.key.keysym.sym;
223 if(tux.key_event(key,DOWN))
228 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
236 case SDL_KEYUP: /* A keyrelease! */
238 SDLKey key = event.key.keysym.sym;
240 if(tux.key_event(key, UP))
251 st_pause_ticks_stop();
256 st_pause_ticks_start();
263 tux.size = !tux.size;
266 tux.base.height = 64;
269 tux.base.height = 32;
274 player_status.distros += 50;
282 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
286 --player_status.lives;
290 player_status.score += 1000;
303 case SDL_JOYAXISMOTION:
304 if (event.jaxis.axis == joystick_keymap.x_axis)
306 if (event.jaxis.value < -joystick_keymap.dead_zone)
308 tux.input.left = DOWN;
309 tux.input.right = UP;
311 else if (event.jaxis.value > joystick_keymap.dead_zone)
314 tux.input.right = DOWN;
318 tux.input.left = DOWN;
319 tux.input.right = DOWN;
322 else if (event.jaxis.axis == joystick_keymap.y_axis)
324 if (event.jaxis.value > joystick_keymap.dead_zone)
325 tux.input.down = DOWN;
326 else if (event.jaxis.value < -joystick_keymap.dead_zone)
333 case SDL_JOYBUTTONDOWN:
334 if (event.jbutton.button == joystick_keymap.a_button)
336 else if (event.jbutton.button == joystick_keymap.b_button)
337 tux.input.fire = DOWN;
338 else if (event.jbutton.button == joystick_keymap.start_button)
341 case SDL_JOYBUTTONUP:
342 if (event.jbutton.button == joystick_keymap.a_button)
344 else if (event.jbutton.button == joystick_keymap.b_button)
358 GameSession::check_end_conditions()
360 Player* tux = world->get_tux();
363 if (tux->base.x >= World::current()->get_level()->endpos + 320)
365 exit_status = LEVEL_FINISHED;
367 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequenze)
375 // Check End conditions
378 player_status.lives -= 1;
380 if (player_status.lives < 0)
382 if(st_gl_mode != ST_GL_TEST)
385 exit_status = GAME_OVER;
388 { // Still has lives, so reset Tux to the levelstart
396 GameSession::action(double frame_ratio)
398 check_end_conditions();
400 if (exit_status == NONE)
402 // Update Tux and the World
403 world->action(frame_ratio);
415 int x = screen->h / 20;
416 for(int i = 0; i < x; ++i)
418 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);
420 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
421 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
426 Menu::current()->draw();
427 mouse_cursor->draw();
434 GameSession::process_menu()
436 Menu* menu = Menu::current();
441 if(menu == game_menu)
443 switch (game_menu->check())
446 st_pause_ticks_stop();
449 st_pause_ticks_stop();
450 exit_status = LEVEL_ABORT;
454 else if(menu == options_menu)
456 process_options_menu();
458 else if(menu == load_game_menu )
460 process_load_game_menu();
465 GameSession::ExitStatus
468 Menu::set_current(0);
469 Player* tux = world->get_tux();
474 global_frame_counter = 0;
477 fps_timer.init(true);
478 frame_timer.init(true);
480 last_update_time = st_get_ticks();
484 clearscreen(0, 0, 0);
488 play_current_music();
490 // Eat unneeded events
492 while (SDL_PollEvent(&event)) {}
496 float overlap = 0.0f;
497 while (exit_status == NONE)
499 /* Calculate the movement-factor */
500 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
502 if(!frame_timer.check())
504 frame_timer.start(25);
505 ++global_frame_counter;
509 tux->input.old_fire = tux->input.fire;
514 // Update the world state and all objects in the world
515 // Do that with a constante time-delta so that the game will run
516 // determistic and not different on different machines
517 if(!game_pause && !Menu::current())
519 frame_ratio *= game_speed;
520 frame_ratio += overlap;
521 while (frame_ratio > 0)
530 overlap = frame_ratio;
540 /* Time stops in pause mode */
541 if(game_pause || Menu::current())
546 /* Set the time of the last update and the time of the current update */
547 last_update_time = update_time;
548 update_time = st_get_ticks();
550 /* Pause till next frame, if the machine running the game is too fast: */
551 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
552 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
553 if(last_update_time >= update_time - 12)
556 update_time = st_get_ticks();
560 if (time_left.check())
562 /* are we low on time ? */
563 if (time_left.get_left() < TIME_WARNING
564 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
566 set_current_music(HURRYUP_MUSIC);
567 play_current_music();
570 else if(tux->dying == DYING_NOT)
575 /* Calculate frames per second */
579 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
581 if(!fps_timer.check())
583 fps_timer.start(1000);
591 world->get_level()->free_gfx();
592 world->get_level()->cleanup();
593 world->get_level()->free_song();
598 /* Bounce a brick: */
599 void bumpbrick(float x, float y)
601 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
604 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
609 GameSession::drawstatus()
613 sprintf(str, "%d", player_status.score);
614 white_text->draw("SCORE", 0, 0, 1);
615 gold_text->draw(str, 96, 0, 1);
617 if(st_gl_mode == ST_GL_TEST)
619 white_text->draw("Press ESC To Return",0,20,1);
622 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
624 sprintf(str, "%d", time_left.get_left() / 1000 );
625 white_text->draw("TIME", 224, 0, 1);
626 gold_text->draw(str, 304, 0, 1);
629 sprintf(str, "%d", player_status.distros);
630 white_text->draw("DISTROS", screen->h, 0, 1);
631 gold_text->draw(str, 608, 0, 1);
633 white_text->draw("LIVES", screen->h, 20, 1);
637 sprintf(str, "%2.1f", fps_fps);
638 white_text->draw("FPS", screen->h, 40, 1);
639 gold_text->draw(str, screen->h + 60, 40, 1);
642 for(int i= 0; i < player_status.lives; ++i)
644 tux_life->draw(565+(18*i),20);
649 GameSession::drawendscreen()
653 clearscreen(0, 0, 0);
655 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
657 sprintf(str, "SCORE: %d", player_status.score);
658 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
660 sprintf(str, "COINS: %d", player_status.distros);
661 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
666 wait_for_event(event,2000,5000,true);
670 GameSession::drawresultscreen(void)
674 clearscreen(0, 0, 0);
676 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
678 sprintf(str, "SCORE: %d", player_status.score);
679 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
681 sprintf(str, "DISTROS: %d", player_status.distros);
682 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
687 wait_for_event(event,2000,5000,true);
690 std::string slotinfo(int slot)
694 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
696 if (access(slotfile, F_OK) == 0)
697 sprintf(tmp,"Slot %d - Savegame",slot);
699 sprintf(tmp,"Slot %d - Free",slot);