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);
477 Player* tux = world->get_tux();
482 update_time = last_update_time = st_get_ticks();
485 clearscreen(0, 0, 0);
488 // Eat unneeded events
490 while (SDL_PollEvent(&event)) {}
494 float overlap = 0.0f;
495 while (exit_status == NONE)
497 /* Calculate the movement-factor */
498 double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
500 if(!frame_timer.check())
502 frame_timer.start(25);
503 ++global_frame_counter;
507 tux->input.old_fire = tux->input.fire;
512 // Update the world state and all objects in the world
513 // Do that with a constante time-delta so that the game will run
514 // determistic and not different on different machines
515 if(!game_pause && !Menu::current())
517 frame_ratio *= game_speed;
518 frame_ratio += overlap;
519 while (frame_ratio > 0)
528 overlap = frame_ratio;
538 /* Time stops in pause mode */
539 if(game_pause || Menu::current())
544 /* Set the time of the last update and the time of the current update */
545 last_update_time = update_time;
546 update_time = st_get_ticks();
548 /* Pause till next frame, if the machine running the game is too fast: */
549 /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But
550 the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */
551 if(last_update_time >= update_time - 12)
554 update_time = st_get_ticks();
558 if (!time_left.check() && tux->dying == DYING_NOT)
562 if(tux->invincible_timer.check())
564 if(world->get_music_type() != HERRING_MUSIC)
565 world->play_music(HERRING_MUSIC);
567 /* are we low on time ? */
568 else if (time_left.get_left() < TIME_WARNING
569 && (world->get_music_type() == LEVEL_MUSIC))
571 world->play_music(HURRYUP_MUSIC);
573 /* or just normal music? */
574 else if(world->get_music_type() != LEVEL_MUSIC)
576 world->play_music(LEVEL_MUSIC);
579 /* Calculate frames per second */
583 fps_fps = (1000.0 / (float)fps_timer.get_gone()) * (float)fps_cnt;
585 if(!fps_timer.check())
587 fps_timer.start(1000);
599 /* Bounce a brick: */
600 void bumpbrick(float x, float y)
602 World::current()->add_bouncy_brick(((int)(x + 1) / 32) * 32,
605 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
610 GameSession::drawstatus()
614 sprintf(str, "%d", player_status.score);
615 white_text->draw("SCORE", 0, 0, 1);
616 gold_text->draw(str, 96, 0, 1);
618 if(st_gl_mode == ST_GL_TEST)
620 white_text->draw("Press ESC To Return",0,20,1);
623 if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5)
625 sprintf(str, "%d", time_left.get_left() / 1000 );
626 white_text->draw("TIME", 224, 0, 1);
627 gold_text->draw(str, 304, 0, 1);
630 sprintf(str, "%d", player_status.distros);
631 white_text->draw("DISTROS", screen->h, 0, 1);
632 gold_text->draw(str, 608, 0, 1);
634 white_text->draw("LIVES", screen->h, 20, 1);
638 sprintf(str, "%2.1f", fps_fps);
639 white_text->draw("FPS", screen->h, 40, 1);
640 gold_text->draw(str, screen->h + 60, 40, 1);
643 for(int i= 0; i < player_status.lives; ++i)
645 tux_life->draw(565+(18*i),20);
650 GameSession::drawendscreen()
654 clearscreen(0, 0, 0);
656 blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1);
658 sprintf(str, "SCORE: %d", player_status.score);
659 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
661 sprintf(str, "COINS: %d", player_status.distros);
662 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
667 wait_for_event(event,2000,5000,true);
671 GameSession::drawresultscreen(void)
675 clearscreen(0, 0, 0);
677 blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1);
679 sprintf(str, "SCORE: %d", player_status.score);
680 gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1);
682 sprintf(str, "DISTROS: %d", player_status.distros);
683 gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1);
688 wait_for_event(event,2000,5000,true);
691 std::string slotinfo(int slot)
695 sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot);
697 if (access(slotfile, F_OK) == 0)
698 sprintf(tmp,"Slot %d - Savegame",slot);
700 sprintf(tmp,"Slot %d - Free",slot);