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()
176 if(st_gl_mode == ST_GL_TEST)
178 exit_status = LEVEL_ABORT;
180 else if (!Menu::current())
182 Menu::set_current(game_menu);
187 GameSession::process_events()
191 Player& tux = *world->get_tux();
194 tux.input.right = DOWN;
197 if (int(last_x_pos) == int(tux.base.x))
202 last_x_pos = tux.base.x;
207 while (SDL_PollEvent(&event))
209 /* Check for menu-events, if the menu is shown */
212 Menu::current()->event(event);
213 st_pause_ticks_start();
217 Player& tux = *world->get_tux();
219 st_pause_ticks_stop();
223 case SDL_QUIT: /* Quit event - quit: */
224 st_abort("Received window close", "");
227 case SDL_KEYDOWN: /* A keypress! */
229 SDLKey key = event.key.keysym.sym;
231 if(tux.key_event(key,DOWN))
236 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
244 case SDL_KEYUP: /* A keyrelease! */
246 SDLKey key = event.key.keysym.sym;
248 if(tux.key_event(key, UP))
259 st_pause_ticks_stop();
264 st_pause_ticks_start();
271 tux.size = !tux.size;
274 tux.base.height = 64;
277 tux.base.height = 32;
282 player_status.distros += 50;
290 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
294 --player_status.lives;
298 player_status.score += 1000;
311 case SDL_JOYAXISMOTION:
312 if (event.jaxis.axis == joystick_keymap.x_axis)
314 if (event.jaxis.value < -joystick_keymap.dead_zone)
316 tux.input.left = DOWN;
317 tux.input.right = UP;
319 else if (event.jaxis.value > joystick_keymap.dead_zone)
322 tux.input.right = DOWN;
326 tux.input.left = DOWN;
327 tux.input.right = DOWN;
330 else if (event.jaxis.axis == joystick_keymap.y_axis)
332 if (event.jaxis.value > joystick_keymap.dead_zone)
333 tux.input.down = DOWN;
334 else if (event.jaxis.value < -joystick_keymap.dead_zone)
341 case SDL_JOYBUTTONDOWN:
342 if (event.jbutton.button == joystick_keymap.a_button)
344 else if (event.jbutton.button == joystick_keymap.b_button)
345 tux.input.fire = DOWN;
346 else if (event.jbutton.button == joystick_keymap.start_button)
349 case SDL_JOYBUTTONUP:
350 if (event.jbutton.button == joystick_keymap.a_button)
352 else if (event.jbutton.button == joystick_keymap.b_button)
366 GameSession::check_end_conditions()
368 Player* tux = world->get_tux();
371 if (tux->base.x >= World::current()->get_level()->endpos + 320)
373 exit_status = LEVEL_FINISHED;
375 else if (tux->base.x >= World::current()->get_level()->endpos && !end_sequenze)
383 // Check End conditions
386 player_status.lives -= 1;
388 if (player_status.lives < 0)
390 if(st_gl_mode != ST_GL_TEST)
393 exit_status = GAME_OVER;
396 { // Still has lives, so reset Tux to the levelstart
404 GameSession::action(double frame_ratio)
406 check_end_conditions();
408 if (exit_status == NONE)
410 // Update Tux and the World
411 world->action(frame_ratio);
423 int x = screen->h / 20;
424 for(int i = 0; i < x; ++i)
426 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);
428 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
429 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
434 Menu::current()->draw();
435 mouse_cursor->draw();
442 GameSession::process_menu()
444 Menu* menu = Menu::current();
449 if(menu == game_menu)
451 switch (game_menu->check())
454 st_pause_ticks_stop();
457 st_pause_ticks_stop();
458 exit_status = LEVEL_ABORT;
462 else if(menu == options_menu)
464 process_options_menu();
466 else if(menu == load_game_menu )
468 process_load_game_menu();
473 GameSession::ExitStatus
476 Menu::set_current(0);
481 update_time = last_update_time = st_get_ticks();
484 clearscreen(0, 0, 0);
487 // Eat unneeded events
489 while (SDL_PollEvent(&event)) {}
493 float overlap = 0.0f;
494 while (exit_status == NONE)
496 /* Calculate the movement-factor */
497 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
499 if(!frame_timer.check())
501 frame_timer.start(25);
502 ++global_frame_counter;
506 world->get_tux()->input.old_fire = world->get_tux()->input.fire;
511 // Update the world state and all objects in the world
512 // Do that with a constante time-delta so that the game will run
513 // determistic and not different on different machines
514 if(!game_pause && !Menu::current())
516 frame_ratio *= game_speed;
517 frame_ratio += overlap;
518 while (frame_ratio > 0)
527 overlap = frame_ratio;
537 /* Time stops in pause mode */
538 if(game_pause || Menu::current())
543 /* Set the time of the last update and the time of the current update */
544 last_update_time = update_time;
545 update_time = st_get_ticks();
547 /* Pause till next frame, if the machine running the game is too fast: */
548 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
549 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
550 if(last_update_time >= update_time - 12)
553 update_time = st_get_ticks();
557 if (!time_left.check() && world->get_tux()->dying == DYING_NOT)
558 world->get_tux()->kill(KILL);
561 if(world->get_tux()->invincible_timer.check())
563 if(world->get_music_type() != HERRING_MUSIC)
564 world->play_music(HERRING_MUSIC);
566 /* are we low on time ? */
567 else if (time_left.get_left() < TIME_WARNING
568 && (world->get_music_type() == LEVEL_MUSIC))
570 world->play_music(HURRYUP_MUSIC);
572 /* or just normal music? */
573 else if(world->get_music_type() != LEVEL_MUSIC)
575 world->play_music(LEVEL_MUSIC);
578 /* Calculate frames per second */
582 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
584 if(!fps_timer.check())
586 fps_timer.start(1000);
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);