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_)
67 GameSession::restart_level()
73 frame_timer.init(true);
78 { // Tux has lost a life, so we try to respawn him at the nearest reset point
79 old_x_pos = world->get_tux()->base.x;
84 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
86 world = new World(subset);
88 else if (st_gl_mode == ST_GL_DEMO_GAME)
90 world = new World(subset);
94 world = new World(subset, levelnb);
97 // Set Tux to the nearest reset point
100 ResetPoint best_reset_point = { -1, -1 };
101 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
102 i != get_level()->reset_points.end(); ++i)
104 if (i->x < old_x_pos && best_reset_point.x < i->x)
105 best_reset_point = *i;
108 if (best_reset_point.x != -1)
110 world->get_tux()->base.x = best_reset_point.x;
111 world->get_tux()->base.y = best_reset_point.y;
116 if (st_gl_mode != ST_GL_DEMO_GAME)
118 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
122 time_left.init(true);
126 GameSession::~GameSession()
132 GameSession::levelintro(void)
136 clearscreen(0, 0, 0);
138 sprintf(str, "%s", world->get_level()->name.c_str());
139 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
141 sprintf(str, "TUX x %d", player_status.lives);
142 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
144 sprintf(str, "by %s", world->get_level()->author.c_str());
145 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
151 wait_for_event(event,1000,3000,true);
156 GameSession::start_timers()
158 time_left.start(world->get_level()->time_left*1000);
159 st_pause_ticks_init();
160 update_time = st_get_ticks();
164 GameSession::on_escape_press()
166 if(st_gl_mode == ST_GL_TEST)
168 exit_status = LEVEL_ABORT;
170 else if (!Menu::current())
172 Menu::set_current(game_menu);
177 GameSession::process_events()
179 Player& tux = *world->get_tux();
182 while (SDL_PollEvent(&event))
184 /* Check for menu-events, if the menu is shown */
187 Menu::current()->event(event);
188 st_pause_ticks_start();
192 st_pause_ticks_stop();
196 case SDL_QUIT: /* Quit event - quit: */
197 st_abort("Received window close", "");
200 case SDL_KEYDOWN: /* A keypress! */
202 SDLKey key = event.key.keysym.sym;
204 if(tux.key_event(key,DOWN))
209 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
217 case SDL_KEYUP: /* A keyrelease! */
219 SDLKey key = event.key.keysym.sym;
221 if(tux.key_event(key, UP))
232 st_pause_ticks_stop();
237 st_pause_ticks_start();
244 tux.size = !tux.size;
247 tux.base.height = 64;
250 tux.base.height = 32;
255 player_status.distros += 50;
263 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
267 --player_status.lives;
271 player_status.score += 1000;
284 case SDL_JOYAXISMOTION:
285 if (event.jaxis.axis == joystick_keymap.x_axis)
287 if (event.jaxis.value < -joystick_keymap.dead_zone)
289 tux.input.left = DOWN;
290 tux.input.right = UP;
292 else if (event.jaxis.value > joystick_keymap.dead_zone)
295 tux.input.right = DOWN;
299 tux.input.left = DOWN;
300 tux.input.right = DOWN;
303 else if (event.jaxis.axis == joystick_keymap.y_axis)
305 if (event.jaxis.value > joystick_keymap.dead_zone)
306 tux.input.down = DOWN;
307 else if (event.jaxis.value < -joystick_keymap.dead_zone)
314 case SDL_JOYBUTTONDOWN:
315 if (event.jbutton.button == joystick_keymap.a_button)
317 else if (event.jbutton.button == joystick_keymap.b_button)
318 tux.input.fire = DOWN;
319 else if (event.jbutton.button == joystick_keymap.start_button)
322 case SDL_JOYBUTTONUP:
323 if (event.jbutton.button == joystick_keymap.a_button)
325 else if (event.jbutton.button == joystick_keymap.b_button)
338 GameSession::check_end_conditions()
340 Player* tux = world->get_tux();
343 if (tux->base.x >= World::current()->get_level()->endpos
344 && World::current()->get_level()->endpos != 0)
346 exit_status = LEVEL_FINISHED;
350 // Check End conditions
353 player_status.lives -= 1;
355 if (player_status.lives < 0)
357 if(st_gl_mode != ST_GL_TEST)
360 exit_status = GAME_OVER;
363 { // Still has lives, so reset Tux to the levelstart
371 GameSession::action(double frame_ratio)
373 check_end_conditions();
375 if (exit_status == NONE)
377 // Update Tux and the World
378 world->action(frame_ratio);
390 int x = screen->h / 20;
391 for(int i = 0; i < x; ++i)
393 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);
395 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
396 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
401 Menu::current()->draw();
402 mouse_cursor->draw();
409 GameSession::ExitStatus
412 Menu::set_current(0);
413 Player* tux = world->get_tux();
418 global_frame_counter = 0;
421 fps_timer.init(true);
422 frame_timer.init(true);
424 last_update_time = st_get_ticks();
428 clearscreen(0, 0, 0);
432 play_current_music();
434 // Eat unneeded events
436 while (SDL_PollEvent(&event)) {}
440 float overlap = 0.0f;
441 while (exit_status == NONE)
443 /* Calculate the movement-factor */
444 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
446 if(!frame_timer.check())
448 frame_timer.start(25);
449 ++global_frame_counter;
453 tux->input.old_fire = tux->input.fire;
457 Menu* menu = Menu::current();
462 if(menu == game_menu)
464 switch (game_menu->check())
467 st_pause_ticks_stop();
470 st_pause_ticks_stop();
471 exit_status = LEVEL_ABORT;
475 else if(menu == options_menu)
477 process_options_menu();
479 else if(menu == load_game_menu )
481 process_load_game_menu();
486 if(!game_pause && !Menu::current())
488 frame_ratio *= game_speed;
489 frame_ratio += overlap;
490 while (frame_ratio > 0)
495 overlap = frame_ratio;
503 if(debug_mode && debug_fps)
506 /*Draw the current scene to the screen */
507 /*If the machine running the game is too slow
508 skip the drawing of the frame (so the calculations are more precise and
509 the FPS aren't affected).*/
510 /*if( ! fps_fps < 50.0 )
513 jump = true;*/ /*FIXME: Implement this tweak right.*/
516 /* Time stops in pause mode */
517 if(game_pause || Menu::current())
522 /* Set the time of the last update and the time of the current update */
523 last_update_time = update_time;
524 update_time = st_get_ticks();
526 /* Pause till next frame, if the machine running the game is too fast: */
527 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
528 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
529 if(last_update_time >= update_time - 12) {
531 update_time = st_get_ticks();
533 /*if((update_time - last_update_time) < 10)
534 SDL_Delay((11 - (update_time - last_update_time))/2);*/
537 if (time_left.check())
539 /* are we low on time ? */
540 if (time_left.get_left() < TIME_WARNING
541 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
543 set_current_music(HURRYUP_MUSIC);
544 play_current_music();
547 else if(tux->dying == DYING_NOT)
550 /* Calculate frames per second */
554 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
556 if(!fps_timer.check())
558 fps_timer.start(1000);
566 world->get_level()->free_gfx();
567 world->get_level()->cleanup();
568 world->get_level()->free_song();
573 /* Bounce a brick: */
574 void bumpbrick(float x, float y)
576 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
579 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
584 GameSession::drawstatus()
588 sprintf(str, "%d", player_status.score);
589 white_text->draw("SCORE", 0, 0, 1);
590 gold_text->draw(str, 96, 0, 1);
592 if(st_gl_mode == ST_GL_TEST)
594 white_text->draw("Press ESC To Return",0,20,1);
597 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
599 sprintf(str, "%d", time_left.get_left() / 1000 );
600 white_text->draw("TIME", 224, 0, 1);
601 gold_text->draw(str, 304, 0, 1);
604 sprintf(str, "%d", player_status.distros);
605 white_text->draw("DISTROS", screen->h, 0, 1);
606 gold_text->draw(str, 608, 0, 1);
608 white_text->draw("LIVES", screen->h, 20, 1);
612 sprintf(str, "%2.1f", fps_fps);
613 white_text->draw("FPS", screen->h, 40, 1);
614 gold_text->draw(str, screen->h + 60, 40, 1);
617 for(int i= 0; i < player_status.lives; ++i)
619 tux_life->draw(565+(18*i),20);
624 GameSession::drawendscreen()
628 clearscreen(0, 0, 0);
630 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
632 sprintf(str, "SCORE: %d", player_status.score);
633 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
635 sprintf(str, "COINS: %d", player_status.distros);
636 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
641 wait_for_event(event,2000,5000,true);
645 GameSession::drawresultscreen(void)
649 clearscreen(0, 0, 0);
651 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
653 sprintf(str, "SCORE: %d", player_status.score);
654 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
656 sprintf(str, "DISTROS: %d", player_status.distros);
657 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
662 wait_for_event(event,2000,5000,true);
665 std::string slotinfo(int slot)
669 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
671 if (access(slotfile, F_OK) == 0)
672 sprintf(tmp,"Slot %d - Savegame",slot);
674 sprintf(tmp,"Slot %d - Free",slot);