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()
74 frame_timer.init(true);
79 { // Tux has lost a life, so we try to respawn him at the nearest reset point
80 old_x_pos = world->get_tux()->base.x;
85 if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
87 world = new World(subset);
89 else if (st_gl_mode == ST_GL_DEMO_GAME)
91 world = new World(subset);
95 world = new World(subset, levelnb);
98 // Set Tux to the nearest reset point
101 ResetPoint best_reset_point = { -1, -1 };
102 for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
103 i != get_level()->reset_points.end(); ++i)
105 if (i->x < old_x_pos && best_reset_point.x < i->x)
106 best_reset_point = *i;
109 if (best_reset_point.x != -1)
111 world->get_tux()->base.x = best_reset_point.x;
112 world->get_tux()->base.y = best_reset_point.y;
117 if (st_gl_mode != ST_GL_DEMO_GAME)
119 if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
123 time_left.init(true);
127 GameSession::~GameSession()
133 GameSession::levelintro(void)
137 clearscreen(0, 0, 0);
139 sprintf(str, "%s", world->get_level()->name.c_str());
140 gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1);
142 sprintf(str, "TUX x %d", player_status.lives);
143 white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
145 sprintf(str, "by %s", world->get_level()->author.c_str());
146 white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1);
152 wait_for_event(event,1000,3000,true);
157 GameSession::start_timers()
159 time_left.start(world->get_level()->time_left*1000);
160 st_pause_ticks_init();
161 update_time = st_get_ticks();
165 GameSession::on_escape_press()
167 if(st_gl_mode == ST_GL_TEST)
169 exit_status = LEVEL_ABORT;
171 else if (!Menu::current())
173 Menu::set_current(game_menu);
178 GameSession::process_events()
181 while (SDL_PollEvent(&event))
183 /* Check for menu-events, if the menu is shown */
186 Menu::current()->event(event);
187 st_pause_ticks_start();
189 else if (end_sequenze)
191 Player& tux = *world->get_tux();
193 tux.input.right = DOWN;
199 Player& tux = *world->get_tux();
201 st_pause_ticks_stop();
205 case SDL_QUIT: /* Quit event - quit: */
206 st_abort("Received window close", "");
209 case SDL_KEYDOWN: /* A keypress! */
211 SDLKey key = event.key.keysym.sym;
213 if(tux.key_event(key,DOWN))
218 case SDLK_ESCAPE: /* Escape: Open/Close the menu: */
226 case SDL_KEYUP: /* A keyrelease! */
228 SDLKey key = event.key.keysym.sym;
230 if(tux.key_event(key, UP))
241 st_pause_ticks_stop();
246 st_pause_ticks_start();
253 tux.size = !tux.size;
256 tux.base.height = 64;
259 tux.base.height = 32;
264 player_status.distros += 50;
272 tux.invincible_timer.start(TUX_INVINCIBLE_TIME);
276 --player_status.lives;
280 player_status.score += 1000;
293 case SDL_JOYAXISMOTION:
294 if (event.jaxis.axis == joystick_keymap.x_axis)
296 if (event.jaxis.value < -joystick_keymap.dead_zone)
298 tux.input.left = DOWN;
299 tux.input.right = UP;
301 else if (event.jaxis.value > joystick_keymap.dead_zone)
304 tux.input.right = DOWN;
308 tux.input.left = DOWN;
309 tux.input.right = DOWN;
312 else if (event.jaxis.axis == joystick_keymap.y_axis)
314 if (event.jaxis.value > joystick_keymap.dead_zone)
315 tux.input.down = DOWN;
316 else if (event.jaxis.value < -joystick_keymap.dead_zone)
323 case SDL_JOYBUTTONDOWN:
324 if (event.jbutton.button == joystick_keymap.a_button)
326 else if (event.jbutton.button == joystick_keymap.b_button)
327 tux.input.fire = DOWN;
328 else if (event.jbutton.button == joystick_keymap.start_button)
331 case SDL_JOYBUTTONUP:
332 if (event.jbutton.button == joystick_keymap.a_button)
334 else if (event.jbutton.button == joystick_keymap.b_button)
347 GameSession::check_end_conditions()
349 Player* tux = world->get_tux();
352 if (tux->base.x >= World::current()->get_level()->endpos + 320)
354 exit_status = LEVEL_FINISHED;
356 else if (tux->base.x >= World::current()->get_level()->endpos)
363 // Check End conditions
366 player_status.lives -= 1;
368 if (player_status.lives < 0)
370 if(st_gl_mode != ST_GL_TEST)
373 exit_status = GAME_OVER;
376 { // Still has lives, so reset Tux to the levelstart
384 GameSession::action(double frame_ratio)
386 check_end_conditions();
388 if (exit_status == NONE)
390 // Update Tux and the World
391 world->action(frame_ratio);
403 int x = screen->h / 20;
404 for(int i = 0; i < x; ++i)
406 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);
408 fillrect(0,0,screen->w,screen->h,rand() % 50, rand() % 50, rand() % 50, 128);
409 blue_text->drawf("PAUSE - Press 'P' To Play", 0, 230, A_HMIDDLE, A_TOP, 1);
414 Menu::current()->draw();
415 mouse_cursor->draw();
422 GameSession::process_menu()
424 Menu* menu = Menu::current();
429 if(menu == game_menu)
431 switch (game_menu->check())
434 st_pause_ticks_stop();
437 st_pause_ticks_stop();
438 exit_status = LEVEL_ABORT;
442 else if(menu == options_menu)
444 process_options_menu();
446 else if(menu == load_game_menu )
448 process_load_game_menu();
453 GameSession::ExitStatus
456 Menu::set_current(0);
457 Player* tux = world->get_tux();
462 global_frame_counter = 0;
465 fps_timer.init(true);
466 frame_timer.init(true);
468 last_update_time = st_get_ticks();
472 clearscreen(0, 0, 0);
476 play_current_music();
478 // Eat unneeded events
480 while (SDL_PollEvent(&event)) {}
484 float overlap = 0.0f;
485 while (exit_status == NONE)
487 /* Calculate the movement-factor */
488 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
490 if(!frame_timer.check())
492 frame_timer.start(25);
493 ++global_frame_counter;
497 tux->input.old_fire = tux->input.fire;
502 // Update the world state and all objects in the world
503 // Do that with a constante time-delta so that the game will run
504 // determistic and not different on different machines
505 if(!game_pause && !Menu::current())
507 frame_ratio *= game_speed;
508 frame_ratio += overlap;
509 while (frame_ratio > 0)
518 overlap = frame_ratio;
528 /* Time stops in pause mode */
529 if(game_pause || Menu::current())
534 /* Set the time of the last update and the time of the current update */
535 last_update_time = update_time;
536 update_time = st_get_ticks();
538 /* Pause till next frame, if the machine running the game is too fast: */
539 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
540 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
541 if(last_update_time >= update_time - 12)
544 update_time = st_get_ticks();
548 if (time_left.check())
550 /* are we low on time ? */
551 if (time_left.get_left() < TIME_WARNING
552 && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */
554 set_current_music(HURRYUP_MUSIC);
555 play_current_music();
558 else if(tux->dying == DYING_NOT)
563 /* Calculate frames per second */
567 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
569 if(!fps_timer.check())
571 fps_timer.start(1000);
579 world->get_level()->free_gfx();
580 world->get_level()->cleanup();
581 world->get_level()->free_song();
586 /* Bounce a brick: */
587 void bumpbrick(float x, float y)
589 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
592 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
597 GameSession::drawstatus()
601 sprintf(str, "%d", player_status.score);
602 white_text->draw("SCORE", 0, 0, 1);
603 gold_text->draw(str, 96, 0, 1);
605 if(st_gl_mode == ST_GL_TEST)
607 white_text->draw("Press ESC To Return",0,20,1);
610 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
612 sprintf(str, "%d", time_left.get_left() / 1000 );
613 white_text->draw("TIME", 224, 0, 1);
614 gold_text->draw(str, 304, 0, 1);
617 sprintf(str, "%d", player_status.distros);
618 white_text->draw("DISTROS", screen->h, 0, 1);
619 gold_text->draw(str, 608, 0, 1);
621 white_text->draw("LIVES", screen->h, 20, 1);
625 sprintf(str, "%2.1f", fps_fps);
626 white_text->draw("FPS", screen->h, 40, 1);
627 gold_text->draw(str, screen->h + 60, 40, 1);
630 for(int i= 0; i < player_status.lives; ++i)
632 tux_life->draw(565+(18*i),20);
637 GameSession::drawendscreen()
641 clearscreen(0, 0, 0);
643 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
645 sprintf(str, "SCORE: %d", player_status.score);
646 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
648 sprintf(str, "COINS: %d", player_status.distros);
649 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
654 wait_for_event(event,2000,5000,true);
658 GameSession::drawresultscreen(void)
662 clearscreen(0, 0, 0);
664 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
666 sprintf(str, "SCORE: %d", player_status.score);
667 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
669 sprintf(str, "DISTROS: %d", player_status.distros);
670 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
675 wait_for_event(event,2000,5000,true);
678 std::string slotinfo(int slot)
682 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
684 if (access(slotfile, F_OK) == 0)
685 sprintf(tmp,"Slot %d - Savegame",slot);
687 sprintf(tmp,"Slot %d - Free",slot);