X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fgameloop.cpp;h=251dafdcd2fa9bfa2484874073e261f158c243e8;hb=e776775f2ef6a3843cb83b39b34980d98e208f2f;hp=809d9bbd4f9ef8ebb7d1afaa1cd201ab7ef2a613;hpb=b6e8cce81c0c24e4ed693246ad8e9b14c6c28064;p=supertux.git diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 809d9bbd4..251dafdcd 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -53,21 +53,31 @@ #include "tile.h" #include "particlesystem.h" #include "resources.h" +#include "music_manager.h" GameSession* GameSession::current_ = 0; GameSession::GameSession(const std::string& subset_, int levelnb_, int mode) - : world(0), st_gl_mode(mode), levelnb(levelnb_), subset(subset_) + : world(0), st_gl_mode(mode), levelnb(levelnb_), end_sequence(NO_ENDSEQUENCE), + subset(subset_) { current_ = this; + + global_frame_counter = 0; + game_pause = false; + + fps_timer.init(true); + frame_timer.init(true); + restart_level(); } void GameSession::restart_level() { - game_pause = false; - exit_status = NONE; + game_pause = false; + exit_status = ES_NONE; + end_sequence = NO_ENDSEQUENCE; fps_timer.init(true); frame_timer.init(true); @@ -111,7 +121,6 @@ GameSession::restart_level() world->get_tux()->base.y = best_reset_point.y; } } - if (st_gl_mode != ST_GL_DEMO_GAME) { @@ -120,7 +129,8 @@ GameSession::restart_level() } time_left.init(true); - start_timers(); + start_timers(); + world->play_music(LEVEL_MUSIC); } GameSession::~GameSession() @@ -131,9 +141,14 @@ GameSession::~GameSession() void GameSession::levelintro(void) { + music_manager->halt_music(); + char str[60]; - /* Level Intro: */ - clearscreen(0, 0, 0); + + if (get_level()->img_bkgd) + get_level()->draw_bg(); + else + drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom); sprintf(str, "%s", world->get_level()->name.c_str()); gold_text->drawf(str, 0, 200, A_HMIDDLE, A_TOP, 1); @@ -142,7 +157,7 @@ GameSession::levelintro(void) white_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1); sprintf(str, "by %s", world->get_level()->author.c_str()); - white_small_text->drawf(str, 0, 400, A_HMIDDLE, A_TOP, 1); + white_small_text->drawf(str, 0, 360, A_HMIDDLE, A_TOP, 1); flipscreen(); @@ -163,45 +178,60 @@ GameSession::start_timers() void GameSession::on_escape_press() { + if(game_pause) + return; + if(st_gl_mode == ST_GL_TEST) { - exit_status = LEVEL_ABORT; + exit_status = ES_LEVEL_ABORT; } else if (!Menu::current()) { Menu::set_current(game_menu); - st_pause_ticks_stop(); + st_pause_ticks_start(); } } void GameSession::process_events() { - Player& tux = *world->get_tux(); - - SDL_Event event; - while (SDL_PollEvent(&event)) + if (end_sequence != NO_ENDSEQUENCE) { - /* Check for menu-events, if the menu is shown */ - if (Menu::current()) - { - Menu::current()->event(event); - } + Player& tux = *world->get_tux(); + + tux.input.fire = UP; + tux.input.left = UP; + tux.input.right = DOWN; + tux.input.down = UP; + + if (int(last_x_pos) == int(tux.base.x)) + tux.input.up = DOWN; else + tux.input.up = UP; + + last_x_pos = tux.base.x; + + SDL_Event event; + while (SDL_PollEvent(&event)) { + /* Check for menu-events, if the menu is shown */ + if (Menu::current()) + { + Menu::current()->event(event); + if(!Menu::current()) + st_pause_ticks_stop(); + } + switch(event.type) { case SDL_QUIT: /* Quit event - quit: */ st_abort("Received window close", ""); break; - + case SDL_KEYDOWN: /* A keypress! */ { SDLKey key = event.key.keysym.sym; - - if(tux.key_event(key,DOWN)) - break; - + switch(key) { case SDLK_ESCAPE: /* Escape: Open/Close the menu: */ @@ -211,166 +241,249 @@ GameSession::process_events() break; } } + + case SDL_JOYBUTTONDOWN: + if (event.jbutton.button == joystick_keymap.start_button) + on_escape_press(); break; - case SDL_KEYUP: /* A keyrelease! */ - { - SDLKey key = event.key.keysym.sym; + } + } + } + else // normal mode + { + if(!Menu::current() && !game_pause) + st_pause_ticks_stop(); - if(tux.key_event(key, UP)) + SDL_Event event; + while (SDL_PollEvent(&event)) + { + /* Check for menu-events, if the menu is shown */ + if (Menu::current()) + { + Menu::current()->event(event); + if(!Menu::current()) + st_pause_ticks_stop(); + + /* Tell Tux that the keys are all down, otherwise + it could have nasty bugs, like going allways to the right + or whatever that key does */ + Player& tux = *world->get_tux(); + tux.key_event((SDLKey)keymap.jump, UP); + tux.key_event((SDLKey)keymap.duck, UP); + tux.key_event((SDLKey)keymap.left, UP); + tux.key_event((SDLKey)keymap.right, UP); + tux.key_event((SDLKey)keymap.fire, UP); + } + else + { + Player& tux = *world->get_tux(); + + switch(event.type) + { + case SDL_QUIT: /* Quit event - quit: */ + st_abort("Received window close", ""); break; - switch(key) + case SDL_KEYDOWN: /* A keypress! */ { - case SDLK_p: - if(!Menu::current()) + SDLKey key = event.key.keysym.sym; + + if(tux.key_event(key,DOWN)) + break; + + switch(key) { - if(game_pause) - { - game_pause = false; - st_pause_ticks_stop(); - } - else - { - game_pause = true; - st_pause_ticks_start(); - } + case SDLK_ESCAPE: /* Escape: Open/Close the menu: */ + on_escape_press(); + break; + default: + break; } - break; - case SDLK_TAB: - if(debug_mode) + } + break; + case SDL_KEYUP: /* A keyrelease! */ + { + SDLKey key = event.key.keysym.sym; + + if(tux.key_event(key, UP)) + break; + + switch(key) { - tux.size = !tux.size; - if(tux.size == BIG) + case SDLK_p: + if(!Menu::current()) + { + if(game_pause) + { + game_pause = false; + st_pause_ticks_stop(); + } + else + { + game_pause = true; + st_pause_ticks_start(); + } + } + break; + case SDLK_TAB: + if(debug_mode) { - tux.base.height = 64; + tux.size = !tux.size; + if(tux.size == BIG) + { + tux.base.height = 64; + } + else + tux.base.height = 32; } + break; + case SDLK_END: + if(debug_mode) + player_status.distros += 50; + break; + case SDLK_DELETE: + if(debug_mode) + tux.got_power = tux.FIRE_POWER; + break; + case SDLK_HOME: + if(debug_mode) + tux.got_power = tux.ICE_POWER; + break; + case SDLK_INSERT: + if(debug_mode) + tux.invincible_timer.start(TUX_INVINCIBLE_TIME); + break; + case SDLK_l: + if(debug_mode) + --player_status.lives; + break; + case SDLK_s: + if(debug_mode) + player_status.score += 1000; + case SDLK_f: + if(debug_fps) + debug_fps = false; else - tux.base.height = 32; + debug_fps = true; + break; + default: + break; } - break; - case SDLK_END: - if(debug_mode) - player_status.distros += 50; - break; - case SDLK_DELETE: - if(debug_mode) - tux.got_coffee = 1; - break; - case SDLK_INSERT: - if(debug_mode) - tux.invincible_timer.start(TUX_INVINCIBLE_TIME); - break; - case SDLK_l: - if(debug_mode) - --player_status.lives; - break; - case SDLK_s: - if(debug_mode) - player_status.score += 1000; - case SDLK_f: - if(debug_fps) - debug_fps = false; - else - debug_fps = true; - break; - default: - break; } - } - break; + break; - case SDL_JOYAXISMOTION: - if (event.jaxis.axis == JOY_X) - { - if (event.jaxis.value < -JOYSTICK_DEAD_ZONE) - { - tux.input.left = DOWN; - tux.input.right = UP; - } - else if (event.jaxis.value > JOYSTICK_DEAD_ZONE) + case SDL_JOYAXISMOTION: + if (event.jaxis.axis == joystick_keymap.x_axis) { - tux.input.left = UP; - tux.input.right = DOWN; + if (event.jaxis.value < -joystick_keymap.dead_zone) + { + tux.input.left = DOWN; + tux.input.right = UP; + } + else if (event.jaxis.value > joystick_keymap.dead_zone) + { + tux.input.left = UP; + tux.input.right = DOWN; + } + else + { + tux.input.left = DOWN; + tux.input.right = DOWN; + } } - else + else if (event.jaxis.axis == joystick_keymap.y_axis) { - tux.input.left = DOWN; - tux.input.right = DOWN; + if (event.jaxis.value > joystick_keymap.dead_zone) + tux.input.down = DOWN; + else if (event.jaxis.value < -joystick_keymap.dead_zone) + tux.input.down = UP; + else + tux.input.down = UP; } - } - else if (event.jaxis.axis == JOY_Y) - { - if (event.jaxis.value > JOYSTICK_DEAD_ZONE) - tux.input.down = DOWN; - else if (event.jaxis.value < -JOYSTICK_DEAD_ZONE) - tux.input.down = UP; - else - tux.input.down = UP; - } - break; + break; - case SDL_JOYBUTTONDOWN: - if (event.jbutton.button == JOY_A) - tux.input.up = DOWN; - else if (event.jbutton.button == JOY_B) - tux.input.fire = DOWN; - else if (event.jbutton.button == JOY_START) - on_escape_press(); - break; - case SDL_JOYBUTTONUP: - if (event.jbutton.button == JOY_A) - tux.input.up = UP; - else if (event.jbutton.button == JOY_B) - tux.input.fire = UP; - break; + case SDL_JOYBUTTONDOWN: + if (event.jbutton.button == joystick_keymap.a_button) + tux.input.up = DOWN; + else if (event.jbutton.button == joystick_keymap.b_button) + tux.input.fire = DOWN; + else if (event.jbutton.button == joystick_keymap.start_button) + on_escape_press(); + break; + case SDL_JOYBUTTONUP: + if (event.jbutton.button == joystick_keymap.a_button) + tux.input.up = UP; + else if (event.jbutton.button == joystick_keymap.b_button) + tux.input.fire = UP; + break; - default: - break; - } /* switch */ - } - } /* while */ + default: + break; + } /* switch */ + } + } /* while */ + } } - void GameSession::check_end_conditions() { Player* tux = world->get_tux(); /* End of level? */ - if (tux->base.x >= World::current()->get_level()->endpos - && World::current()->get_level()->endpos != 0) + int endpos = (World::current()->get_level()->width-5) * 32; + Tile* endtile = collision_goal(tux->base); + + // fallback in case the other endpositions don't trigger + if (!end_sequence && tux->base.x >= endpos) { - exit_status = LEVEL_FINISHED; + end_sequence = ENDSEQUENCE_WAITING; + last_x_pos = -1; + music_manager->play_music(level_end_song, 0); + endsequence_timer.start(7000); + tux->invincible_timer.start(7000); //FIXME: Implement a winning timer for the end sequence (with special winning animation etc.) } - else + else if(end_sequence && !endsequence_timer.check()) { - // Check End conditions - if (tux->is_dead()) - { - player_status.lives -= 1; - - if (player_status.lives < 0) - { // No more lives!? - if(st_gl_mode != ST_GL_TEST) - drawendscreen(); - - exit_status = GAME_OVER; - } - else - { // Still has lives, so reset Tux to the levelstart - restart_level(); - } + exit_status = ES_LEVEL_FINISHED; + return; + } + else if(end_sequence == ENDSEQUENCE_RUNNING && endtile && endtile->data >= 1) + { + end_sequence = ENDSEQUENCE_WAITING; + } + else if(!end_sequence && endtile && endtile->data == 0) + { + end_sequence = ENDSEQUENCE_RUNNING; + last_x_pos = -1; + music_manager->play_music(level_end_song, 0); + endsequence_timer.start(7000); // 5 seconds until we finish the map + tux->invincible_timer.start(7000); //FIXME: Implement a winning timer for the end sequence (with special winning animation etc.) + } + else if (!end_sequence && tux->is_dead()) + { + player_status.bonus = PlayerStatus::NO_BONUS; + + if (player_status.lives < 0) + { // No more lives!? + if(st_gl_mode != ST_GL_TEST) + drawendscreen(); + + exit_status = ES_GAME_OVER; } - } + else + { // Still has lives, so reset Tux to the levelstart + restart_level(); + } + + return; + } } void GameSession::action(double frame_ratio) { - check_end_conditions(); - - if (exit_status == NONE) + if (exit_status == ES_NONE) { // Update Tux and the World world->action(frame_ratio); @@ -403,31 +516,47 @@ GameSession::draw() updatescreen(); } +void +GameSession::process_menu() +{ + Menu* menu = Menu::current(); + if(menu) + { + menu->action(); + + if(menu == game_menu) + { + switch (game_menu->check()) + { + case MNID_CONTINUE: + st_pause_ticks_stop(); + break; + case MNID_ABORTLEVEL: + st_pause_ticks_stop(); + exit_status = ES_LEVEL_ABORT; + break; + } + } + else if(menu == options_menu) + { + process_options_menu(); + } + else if(menu == load_game_menu ) + { + process_load_game_menu(); + } + } +} GameSession::ExitStatus GameSession::run() { Menu::set_current(0); - Player* tux = world->get_tux(); current_ = this; - int fps_cnt; - - global_frame_counter = 0; - game_pause = false; - - fps_timer.init(true); - frame_timer.init(true); + int fps_cnt = 0; - last_update_time = st_get_ticks(); - fps_cnt = 0; - - /* Clear screen: */ - clearscreen(0, 0, 0); - updatescreen(); - - /* Play music: */ - play_current_music(); + update_time = last_update_time = st_get_ticks(); // Eat unneeded events SDL_Event event; @@ -435,8 +564,7 @@ GameSession::run() draw(); - float overlap = 0.0f; - while (exit_status == NONE) + while (exit_status == ES_NONE) { /* Calculate the movement-factor */ double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE); @@ -448,52 +576,22 @@ GameSession::run() } /* Handle events: */ - tux->input.old_fire = tux->input.fire; + world->get_tux()->input.old_fire = world->get_tux()->input.fire; process_events(); - - Menu* menu = Menu::current(); - if(menu) - { - menu->action(); + process_menu(); - if(menu == game_menu) - { - switch (game_menu->check()) - { - case 2: - st_pause_ticks_stop(); - break; - case 5: - st_pause_ticks_stop(); - exit_status = LEVEL_ABORT; - break; - } - } - else if(menu == options_menu) - { - process_options_menu(); - } - else if(menu == load_game_menu ) - { - process_load_game_menu(); - } - } - - // Handle actions: + // Update the world state and all objects in the world + // Do that with a constante time-delta so that the game will run + // determistic and not different on different machines if(!game_pause && !Menu::current()) { - frame_ratio *= game_speed; - frame_ratio += overlap; - while (frame_ratio > 0) - { - action(1.0f); - frame_ratio -= 1.0f; - } - overlap = frame_ratio; - - if (exit_status != NONE) - return exit_status; + // Update the world + check_end_conditions(); + if (end_sequence == ENDSEQUENCE_RUNNING) + action(frame_ratio/2); + else if(end_sequence == NO_ENDSEQUENCE) + action(frame_ratio); } else { @@ -501,17 +599,6 @@ GameSession::run() SDL_Delay(50); } - if(debug_mode && debug_fps) - SDL_Delay(60); - - /*Draw the current scene to the screen */ - /*If the machine running the game is too slow - skip the drawing of the frame (so the calculations are more precise and - the FPS aren't affected).*/ - /*if( ! fps_fps < 50.0 ) - game_draw(); - else - jump = true;*/ /*FIXME: Implement this tweak right.*/ draw(); /* Time stops in pause mode */ @@ -522,31 +609,37 @@ GameSession::run() /* Set the time of the last update and the time of the current update */ last_update_time = update_time; - update_time = st_get_ticks(); + update_time = st_get_ticks(); /* Pause till next frame, if the machine running the game is too fast: */ /* FIXME: Works great for in OpenGl mode, where the CPU doesn't have to do that much. But the results in SDL mode aren't perfect (thought the 100 FPS are reached), even on an AMD2500+. */ - if(last_update_time >= update_time - 12) { - SDL_Delay(10); - update_time = st_get_ticks(); - } - /*if((update_time - last_update_time) < 10) - SDL_Delay((11 - (update_time - last_update_time))/2);*/ + if(last_update_time >= update_time - 12) + { + SDL_Delay(10); + update_time = st_get_ticks(); + } /* Handle time: */ - if (time_left.check()) + if (!time_left.check() && world->get_tux()->dying == DYING_NOT + && !end_sequence) + world->get_tux()->kill(Player::KILL); + + /* Handle music: */ + if(world->get_tux()->invincible_timer.check() && !end_sequence) { - /* are we low on time ? */ - if (time_left.get_left() < TIME_WARNING - && (get_current_music() != HURRYUP_MUSIC)) /* play the fast music */ - { - set_current_music(HURRYUP_MUSIC); - play_current_music(); - } + world->play_music(HERRING_MUSIC); + } + /* are we low on time ? */ + else if (time_left.get_left() < TIME_WARNING && !end_sequence) + { + world->play_music(HURRYUP_MUSIC); + } + /* or just normal music? */ + else if(world->get_music_type() != LEVEL_MUSIC && !end_sequence) + { + world->play_music(LEVEL_MUSIC); } - else if(tux->dying == DYING_NOT) - tux->kill(KILL); /* Calculate frames per second */ if(show_fps) @@ -561,13 +654,7 @@ GameSession::run() } } } - - halt_music(); - - world->get_level()->free_gfx(); - world->get_level()->cleanup(); - world->get_level()->free_song(); - + return exit_status; } @@ -595,18 +682,30 @@ GameSession::drawstatus() white_text->draw("Press ESC To Return",0,20,1); } - if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5) - { - sprintf(str, "%d", time_left.get_left() / 1000 ); - white_text->draw("TIME", 224, 0, 1); - gold_text->draw(str, 304, 0, 1); - } + if(!time_left.check()) { + white_text->draw("TIME'S UP", 224, 0, 1); + } else if (time_left.get_left() > TIME_WARNING || (global_frame_counter % 10) < 5) { + sprintf(str, "%d", time_left.get_left() / 1000 ); + white_text->draw("TIME", 224, 0, 1); + gold_text->draw(str, 304, 0, 1); + } sprintf(str, "%d", player_status.distros); - white_text->draw("DISTROS", screen->h, 0, 1); + white_text->draw("COINS", screen->h, 0, 1); gold_text->draw(str, 608, 0, 1); - white_text->draw("LIVES", screen->h, 20, 1); + white_text->draw("LIVES", 480, 20); + if (player_status.lives >= 5) + { + sprintf(str, "%dx", player_status.lives); + gold_text->draw_align(str, 617, 20, A_RIGHT, A_TOP); + tux_life->draw(565+(18*3), 20); + } + else + { + for(int i= 0; i < player_status.lives; ++i) + tux_life->draw(565+(18*i),20); + } if(show_fps) { @@ -614,11 +713,6 @@ GameSession::drawstatus() white_text->draw("FPS", screen->h, 40, 1); gold_text->draw(str, screen->h + 60, 40, 1); } - - for(int i= 0; i < player_status.lives; ++i) - { - tux_life->draw(565+(18*i),20); - } } void @@ -626,7 +720,10 @@ GameSession::drawendscreen() { char str[80]; - clearscreen(0, 0, 0); + if (get_level()->img_bkgd) + get_level()->draw_bg(); + else + drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom); blue_text->drawf("GAMEOVER", 0, 200, A_HMIDDLE, A_TOP, 1); @@ -647,14 +744,17 @@ GameSession::drawresultscreen(void) { char str[80]; - clearscreen(0, 0, 0); + if (get_level()->img_bkgd) + get_level()->draw_bg(); + else + drawgradient(get_level()->bkgd_top, get_level()->bkgd_bottom); blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1); sprintf(str, "SCORE: %d", player_status.score); gold_text->drawf(str, 0, 224, A_HMIDDLE, A_TOP, 1); - sprintf(str, "DISTROS: %d", player_status.distros); + sprintf(str, "COINS: %d", player_status.distros); gold_text->drawf(str, 0, 256, A_HMIDDLE, A_TOP, 1); flipscreen(); @@ -667,10 +767,24 @@ std::string slotinfo(int slot) { char tmp[1024]; char slotfile[1024]; + std::string title; sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot); + lisp_object_t* savegame = lisp_read_from_file(slotfile); + if (savegame) + { + LispReader reader(lisp_cdr(savegame)); + reader.read_string("title", &title); + lisp_free(savegame); + } + if (access(slotfile, F_OK) == 0) - sprintf(tmp,"Slot %d - Savegame",slot); + { + if (!title.empty()) + snprintf(tmp,1024,"Slot %d - %s",slot, title.c_str()); + else + snprintf(tmp, 1024,"Slot %d - Savegame",slot); + } else sprintf(tmp,"Slot %d - Free",slot);