X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fgameloop.cpp;h=4431f16f1078c27b18405f738666a97ed203a769;hb=36109a71ec561ea0fbd2e3c81d35488123921b59;hp=0fc9978e429d9b431923f9479f9003af5f738dfe;hpb=1272f522de1d191aabb509a0bc93861f75fbd5b6;p=supertux.git diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 0fc9978e4..4431f16f1 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -20,16 +20,17 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include + +#include "SDL.h" #ifndef WIN32 #include @@ -37,12 +38,12 @@ #endif #include "defines.h" -#include "globals.h" +#include "app/globals.h" #include "gameloop.h" -#include "screen/screen.h" -#include "setup.h" +#include "video/screen.h" +#include "app/setup.h" #include "high_scores.h" -#include "menu.h" +#include "gui/menu.h" #include "badguy.h" #include "sector.h" #include "special.h" @@ -55,13 +56,31 @@ #include "resources.h" #include "background.h" #include "tilemap.h" -#include "gettext.h" +#include "app/gettext.h" +#include "worldmap.h" +#include "intro.h" +#include "misc.h" +#include "camera.h" +#include "statistics.h" GameSession* GameSession::current_ = 0; -GameSession::GameSession(const std::string& levelname_, int mode) +bool compare_last(std::string& haystack, std::string needle) +{ +int haystack_size = haystack.size(); +int needle_size = needle.size(); + +if(haystack_size < needle_size) + return false; + +if(haystack.compare(haystack_size-needle_size, needle_size, needle) == 0) + return true; +return false; +} + +GameSession::GameSession(const std::string& levelname_, int mode, bool flip_level_) : level(0), currentsector(0), st_gl_mode(mode), - end_sequence(NO_ENDSEQUENCE), levelname(levelname_) + end_sequence(NO_ENDSEQUENCE), levelname(levelname_), flip_level(flip_level_) { current_ = this; @@ -69,11 +88,16 @@ GameSession::GameSession(const std::string& levelname_, int mode) game_pause = false; fps_fps = 0; - fps_timer.init(true); + fps_timer.init(true); frame_timer.init(true); + random_timer.init(true); + frame_rate.set_fps(100); context = new DrawingContext(); + if(flip_levels_mode) + flip_level = true; + restart_level(); } @@ -86,51 +110,49 @@ GameSession::restart_level() fps_timer.init(true); frame_timer.init(true); + random_timer.init(true); + + last_keys.clear(); -#if 0 - float old_x_pos = -1; - if (world) + Vector tux_pos = Vector(-1,-1); + if (currentsector) { // Tux has lost a life, so we try to respawn him at the nearest reset point - old_x_pos = world->get_tux()->base.x; + tux_pos = currentsector->player->base; } -#endif delete level; currentsector = 0; level = new Level; level->load(levelname); + if(flip_level) + level->do_vertical_flip(); + currentsector = level->get_sector("main"); if(!currentsector) - st_abort("Level has no main sector.", ""); + Termination::abort("Level has no main sector.", ""); currentsector->activate("main"); -#if 0 // TODO // Set Tux to the nearest reset point - if (old_x_pos != -1) + if(tux_pos.x != -1) { - ResetPoint best_reset_point = { -1, -1 }; - for(std::vector::iterator i = get_level()->reset_points.begin(); - i != get_level()->reset_points.end(); ++i) - { - if (i->x < old_x_pos && best_reset_point.x < i->x) - best_reset_point = *i; - } - - if (best_reset_point.x != -1) - { - world->get_tux()->base.x = best_reset_point.x; - world->get_tux()->base.y = best_reset_point.y; - } - } -#endif + tux_pos = currentsector->get_best_spawn_point(tux_pos); + currentsector->player->base.x = tux_pos.x; + currentsector->player->base.y = tux_pos.y; + // has to reset camera on swapping + currentsector->camera->reset(Vector(currentsector->player->base.x, + currentsector->player->base.y)); + } + if (st_gl_mode != ST_GL_DEMO_GAME) { if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE) levelintro(); } + global_stats.reset(); + time_left.init(true); start_timers(); currentsector->play_music(LEVEL_MUSIC); @@ -145,7 +167,7 @@ GameSession::~GameSession() void GameSession::levelintro(void) { - sound_manager->halt_music(); + SoundManager::get()->halt_music(); char str[60]; @@ -158,11 +180,18 @@ GameSession::levelintro(void) sprintf(str, "TUX x %d", player_status.lives); context.draw_text_center(white_text, str, Vector(0, 240), LAYER_FOREGROUND1); - - context.draw_text_center(white_small_text, + + if(level->get_author().size()) + context.draw_text_center(white_small_text, std::string(_("by ")) + level->get_author(), Vector(0, 400), LAYER_FOREGROUND1); + + if(flip_level) + context.draw_text_center(white_text, + _("Level Vertically Flipped!"), + Vector(0, 310), LAYER_FOREGROUND1); + context.do_drawing(); SDL_Event event; @@ -174,8 +203,8 @@ void GameSession::start_timers() { time_left.start(level->time_left*1000); - st_pause_ticks_init(); - update_time = st_get_ticks(); + Ticks::pause_init(); + frame_rate.start(); } void @@ -204,7 +233,7 @@ GameSession::on_escape_press() tux.key_event((SDLKey)keymap.fire, UP); Menu::set_current(game_menu); - st_pause_ticks_start(); + Ticks::pause_start(); } } @@ -235,13 +264,13 @@ GameSession::process_events() { Menu::current()->event(event); if(!Menu::current()) - st_pause_ticks_stop(); + Ticks::pause_stop(); } switch(event.type) { case SDL_QUIT: /* Quit event - quit: */ - st_abort("Received window close", ""); + Termination::abort("Received window close", ""); break; case SDL_KEYDOWN: /* A keypress! */ @@ -268,7 +297,7 @@ GameSession::process_events() else // normal mode { if(!Menu::current() && !game_pause) - st_pause_ticks_stop(); + Ticks::pause_stop(); SDL_Event event; while (SDL_PollEvent(&event)) @@ -278,7 +307,7 @@ GameSession::process_events() { Menu::current()->event(event); if(!Menu::current()) - st_pause_ticks_stop(); + Ticks::pause_stop(); } else { @@ -287,7 +316,7 @@ GameSession::process_events() switch(event.type) { case SDL_QUIT: /* Quit event - quit: */ - st_abort("Received window close", ""); + Termination::abort("Received window close", ""); break; case SDL_KEYDOWN: /* A keypress! */ @@ -335,54 +364,76 @@ GameSession::process_events() if(game_pause) { game_pause = false; - st_pause_ticks_stop(); + Ticks::pause_stop(); } else { game_pause = true; - st_pause_ticks_start(); + Ticks::pause_start(); } } break; - case SDLK_TAB: - if(debug_mode) - { - tux.grow(false); - } - 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 - debug_fps = true; - break; default: break; } } + + /* Check if chacrater is ASCII */ + char ch[2]; + if((event.key.keysym.unicode & 0xFF80) == 0) + { + ch[0] = event.key.keysym.unicode & 0x7F; + ch[1] = '\0'; + } + last_keys.append(ch); // add to cheat keys + + // Cheating words (the goal of this is really for debugging, + // but could be used for some cheating, nothing wrong with that) + if(compare_last(last_keys, "grow")) + { + tux.grow(false); + last_keys.clear(); + } + if(compare_last(last_keys, "fire")) + { + tux.grow(false); + tux.got_power = tux.FIRE_POWER; + last_keys.clear(); + } + if(compare_last(last_keys, "ice")) + { + tux.grow(false); + tux.got_power = tux.ICE_POWER; + last_keys.clear(); + } + if(compare_last(last_keys, "lifeup")) + { + player_status.lives++; + last_keys.clear(); + // "lifeup" activates pause cause of the 'p' + // so work around to ignore it + if(game_pause) + { + game_pause = false; + Ticks::pause_stop(); + } + else + { + game_pause = true; + Ticks::pause_start(); + } + } + if(compare_last(last_keys, "lifedown")) + { + player_status.lives--; + last_keys.clear(); + } + if(compare_last(last_keys, "invincible")) + { // be invincle for the rest of the level + tux.invincible_timer.start(time_left.get_left()); + last_keys.clear(); + } + break; case SDL_JOYAXISMOTION: @@ -414,6 +465,27 @@ GameSession::process_events() tux.input.down = UP; } break; + + case SDL_JOYHATMOTION: + if(event.jhat.value & SDL_HAT_UP) { + tux.input.up = DOWN; + tux.input.down = UP; + } else if(event.jhat.value & SDL_HAT_DOWN) { + tux.input.up = UP; + tux.input.down = DOWN; + } else if(event.jhat.value & SDL_HAT_LEFT) { + tux.input.left = DOWN; + tux.input.right = UP; + } else if(event.jhat.value & SDL_HAT_RIGHT) { + tux.input.left = UP; + tux.input.right = DOWN; + } else if(event.jhat.value == SDL_HAT_CENTERED) { + tux.input.left = UP; + tux.input.right = UP; + tux.input.up = UP; + tux.input.down = UP; + } + break; case SDL_JOYBUTTONDOWN: if (event.jbutton.button == joystick_keymap.a_button) @@ -458,10 +530,14 @@ GameSession::check_end_conditions() else if(!end_sequence && endtile && endtile->data == 0) { end_sequence = ENDSEQUENCE_RUNNING; + random_timer.start(200); // start 1st firework last_x_pos = -1; - sound_manager->play_music(level_end_song, 0); + SoundManager::get()->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.) + + // add left time to stats + global_stats.set_points(TIME_NEEDED_STAT, time_left.get_gone()); } else if (!end_sequence && tux->is_dead()) { @@ -497,6 +573,22 @@ GameSession::action(double frame_ratio) currentsector->play_music(LEVEL_MUSIC); newsector = newspawnpoint = ""; } + + // on end sequence make a few fireworks + if(end_sequence == ENDSEQUENCE_RUNNING && !random_timer.check()) + { + Vector epicenter = currentsector->camera->get_translation(); + epicenter.x += screen->w * ((float)rand() / RAND_MAX); + epicenter.y += (screen->h/2) * ((float)rand() / RAND_MAX); + + int red = rand() % 255; // calculate firework color + int green = rand() % red; + currentsector->add_particles(epicenter, Vector(1.4,1.4), Vector(0,0), + 45, Color(red,green,0), 3, 1300); + + SoundManager::get()->play_sound(IDToSound(SND_FIREWORKS)); + random_timer.start(rand() % 400 + 600); // next firework + } } void @@ -522,6 +614,18 @@ GameSession::draw() Color(rand() % 50, rand() % 50, rand() % 50, 128), LAYER_FOREGROUND1); context->draw_text_center(blue_text, _("PAUSE - Press 'P' To Play"), Vector(0, 230), LAYER_FOREGROUND1+2); + + char str1[60]; + char str2[124]; + sprintf(str1, _("Playing: ")); + sprintf(str2, level->name.c_str()); + + context->draw_text(blue_text, str1, + Vector((screen->w - (blue_text->get_text_width(str1) + white_text->get_text_width(str2)))/2, 340), + LAYER_FOREGROUND1+2); + context->draw_text(white_text, str2, + Vector(((screen->w - (blue_text->get_text_width(str1) + white_text->get_text_width(str2)))/2)+blue_text->get_text_width(str1), 340), + LAYER_FOREGROUND1+2); } if(Menu::current()) @@ -546,10 +650,10 @@ GameSession::process_menu() switch (game_menu->check()) { case MNID_CONTINUE: - st_pause_ticks_stop(); + Ticks::pause_stop(); break; case MNID_ABORTLEVEL: - st_pause_ticks_stop(); + Ticks::pause_stop(); exit_status = ES_LEVEL_ABORT; break; } @@ -573,7 +677,7 @@ GameSession::run() int fps_cnt = 0; - update_time = last_update_time = st_get_ticks(); + frame_rate.start(); // Eat unneeded events SDL_Event event; @@ -584,7 +688,7 @@ GameSession::run() while (exit_status == ES_NONE) { /* Calculate the movement-factor */ - double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE); + double frame_ratio = frame_rate.get(); if(!frame_timer.check()) { @@ -625,18 +729,7 @@ GameSession::run() continue; } - /* Set the time of the last update and the time of the current update */ - last_update_time = update_time; - 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(); - } + frame_rate.update(); /* Handle time: */ if (!time_left.check() && currentsector->player->dying == DYING_NOT @@ -689,7 +782,7 @@ void bumpbrick(float x, float y) Sector::current()->add_bouncy_brick(Vector(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32)); - sound_manager->play_sound(sounds[SND_BRICK], Vector(x, y)); + SoundManager::get()->play_sound(IDToSound(SND_BRICK), Vector(x, y), Sector::current()->player->get_pos()); } /* (Status): */ @@ -698,7 +791,7 @@ GameSession::drawstatus(DrawingContext& context) { char str[60]; - snprintf(str, 60, " %d", player_status.score); + snprintf(str, 60, " %d", global_stats.get_points(SCORE_STAT)); context.draw_text(white_text, _("SCORE"), Vector(0, 0), LAYER_FOREGROUND1); context.draw_text(gold_text, str, Vector(96, 0), LAYER_FOREGROUND1); @@ -721,14 +814,11 @@ GameSession::drawstatus(DrawingContext& context) sprintf(str, " %d", player_status.distros); context.draw_text(white_text, _("COINS"), - Vector(screen->w - white_text->get_text_width(_("COINS"))-white_text->get_text_width(str), 0), + Vector(screen->w - white_text->get_text_width(_("COINS"))-white_text->get_text_width(" 99"), 0), LAYER_FOREGROUND1); context.draw_text(gold_text, str, Vector(screen->w - gold_text->get_text_width(" 99"), 0),LAYER_FOREGROUND1); - context.draw_text(white_text, _("LIVES"), - Vector(screen->w - white_text->get_text_width(_("LIVES"))-white_text->get_text_width(str), 20), - LAYER_FOREGROUND1); if (player_status.lives >= 5) { sprintf(str, "%dx", player_status.lives); @@ -745,11 +835,15 @@ GameSession::drawstatus(DrawingContext& context) LAYER_FOREGROUND1); } + context.draw_text(white_text, _("LIVES"), + Vector(screen->w - white_text->get_text_width(_("LIVES")) - white_text->get_text_width(" 99"), 20), + LAYER_FOREGROUND1); + if(show_fps) { sprintf(str, "%2.1f", fps_fps); context.draw_text(white_text, "FPS", - Vector(screen->w - white_text->get_text_width("FPS "), 40), + Vector(screen->w - white_text->get_text_width("FPS "), 40), LAYER_FOREGROUND1); context.draw_text(gold_text, str, Vector(screen->w-4*16, 40), LAYER_FOREGROUND1); @@ -767,7 +861,7 @@ GameSession::drawresultscreen(void) context.draw_text_center(blue_text, _("Result:"), Vector(0, 200), LAYER_FOREGROUND1); - sprintf(str, _("SCORE: %d"), player_status.score); + sprintf(str, _("SCORE: %d"), global_stats.get_points(SCORE_STAT)); context.draw_text_center(gold_text, str, Vector(0, 224), LAYER_FOREGROUND1); sprintf(str, _("COINS: %d"), player_status.distros); @@ -781,12 +875,14 @@ GameSession::drawresultscreen(void) std::string slotinfo(int slot) { - char tmp[1024]; - char slotfile[1024]; + std::string tmp; + std::string slotfile; std::string title; - sprintf(slotfile,"%s/slot%d.stsg",st_save_dir,slot); + std::stringstream stream; + stream << slot; + slotfile = st_save_dir + "/slot" + stream.str() + ".stsg"; - lisp_object_t* savegame = lisp_read_from_file(slotfile); + lisp_object_t* savegame = lisp_read_from_file(slotfile.c_str()); if (savegame) { LispReader reader(lisp_cdr(savegame)); @@ -794,17 +890,56 @@ std::string slotinfo(int slot) lisp_free(savegame); } - if (access(slotfile, F_OK) == 0) + if (access(slotfile.c_str(), F_OK) == 0) { if (!title.empty()) - snprintf(tmp,1024,"Slot %d - %s",slot, title.c_str()); + tmp = "Slot " + stream.str() + " - " + title; else - snprintf(tmp, 1024,_("Slot %d - Savegame"),slot); + tmp = "Slot " + stream.str() + " - Savegame"; } else - sprintf(tmp,_("Slot %d - Free"),slot); + tmp = std::string(_("Slot")) + " " + stream.str() + " - " + std::string(_("Free")); return tmp; } +bool process_load_game_menu() +{ + int slot = load_game_menu->check(); + + if(slot != -1 && load_game_menu->get_item_by_id(slot).kind == MN_ACTION) + { + std::stringstream stream; + stream << slot; + std::string slotfile = st_save_dir + "/slot" + stream.str() + ".stsg"; + + if (access(slotfile.c_str(), F_OK) != 0) + { + draw_intro(); + } + + // shrink_fade(Point((screen->w/2),(screen->h/2)), 1000); + fadeout(256); + + DrawingContext context; + context.draw_text_center(white_text, "Loading...", + Vector(0, screen->h/2), LAYER_FOREGROUND1); + context.do_drawing(); + + WorldMapNS::WorldMap worldmap; + + // Load the game or at least set the savegame_file variable + worldmap.loadgame(slotfile); + + worldmap.display(); + Menu::set_current(main_menu); + + Ticks::pause_stop(); + return true; + } + else + { + return false; + } +}