Exemple #1
0
void PATHMANAGER::Init(std::ostream & info_output, std::ostream & error_output)
{
	typedef std::vector<fs::path> Paths;

	// Set Ogre plugins dir
	{
		ogre_plugin_dir = "";
		char *plugindir = getenv("OGRE_PLUGIN_DIR");
		if (plugindir) {
			ogre_plugin_dir = plugindir;
		#ifndef _WIN32
		} else if (fs::exists(fs::path(OGRE_PLUGIN_DIR) / "RenderSystem_GL.so")) {
			ogre_plugin_dir = OGRE_PLUGIN_DIR;
		#endif
		} else {
			#ifdef _WIN32
			ogre_plugin_dir = ".";
			#else
			Paths dirs;
			#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(_M_X64)
			dirs.push_back("/usr/local/lib64");
			dirs.push_back("/usr/lib64");
			#else
			dirs.push_back("/usr/local/lib32");
			dirs.push_back("/usr/lib32");
			#endif
			dirs.push_back("/usr/local");
			dirs.push_back("/usr/lib");
			// Loop through the paths and pick the first one that contain a plugin
			for (Paths::const_iterator p = dirs.begin(); p != dirs.end(); ++p) {
				if (fs::exists(*p / "OGRE/RenderSystem_GL.so")) {
					ogre_plugin_dir = (*p / "OGRE").string();
					break;
				} else if (fs::exists(*p / "ogre/RenderSystem_GL.so")) {
					ogre_plugin_dir = (*p / "ogre").string();
					break;
				}
			}
			#endif
		}
	}

	fs::path shortDir = "stuntrally";
	// Figure out the user's home directory
	{
		home_dir = "";
		#ifndef _WIN32 // POSIX
			char *homedir = getenv("HOME");
			if (homedir == NULL)
			{
				home_dir = "/home/";
				homedir = getenv("USER");
				if (homedir == NULL) {
					homedir = getenv("USERNAME");
					if (homedir == NULL) {
						error_output << "Could not find user's home directory!" << std::endl;
						home_dir = "/tmp/";
					}
				}
			}
		#else // Windows
			char *homedir = getenv("USERPROFILE");
			if (homedir == NULL) homedir = "data"; // WIN 9x/Me
		#endif
		home_dir += homedir;
	}

	// Find user's config dir
	#ifndef _WIN32 // POSIX
	{
		char const* conf = getenv("XDG_CONFIG_HOME");
		if (conf) user_config_dir = (fs::path(conf) / "stuntrally").string();
		else user_config_dir = (fs::path(home_dir) / ".config" / "stuntrally").string();
	}
	#else // Windows
	{
		// Open AppData directory
		std::string str;
		ITEMIDLIST* pidl;
		char AppDir[MAX_PATH];
		HRESULT hRes = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE , &pidl);
		if (hRes == NOERROR)
		{
			SHGetPathFromIDList(pidl, AppDir);
			int i;
			for (i = 0; AppDir[i] != '\0'; i++) {
				if (AppDir[i] == '\\') str += '/';
				else str += AppDir[i];
			}
			user_config_dir = (fs::path(str) / "stuntrally").string();
		}
	}
	#endif
	// Create user's config dir
	CreateDir(user_config_dir, error_output);

	// Find user's data dir (for additional data)
	#ifdef _WIN32
	user_data_dir = user_config_dir;  // APPDATA/stuntrally
	#else
	{
		fs::path shareDir = SHARED_DATA_DIR;
		char const* xdg_data_home = getenv("XDG_DATA_HOME");
		user_data_dir = (xdg_data_home ? xdg_data_home / shortDir : fs::path(home_dir) / ".local" / shareDir).string();
	}
	#endif
	// Create user's data dir and its children
	CreateDir(user_data_dir, error_output);
	CreateDir(GetTrackRecordsPath(), error_output);
	CreateDir(GetScreenShotDir(), error_output);
	CreateDir(GetTrackPathUser(), error_output);  // user tracks
	CreateDir(GetTrackPathUser()+"/_previews", error_output);
	CreateDir(GetReplayPath(), error_output);
	CreateDir(GetGhostsPath(), error_output);

	// Find game data dir and defaults config dir
	char *datadir = getenv("STUNTRALLY_DATA_ROOT");
	if (datadir)
		game_data_dir = std::string(datadir);
	else
	{	fs::path shareDir = SHARED_DATA_DIR;
		Paths dirs;

		// Adding users data dir
		// TODO: Disabled for now until this is handled properly
		//dirs.push_back(user_data_dir);

		// Adding relative path from installed executable
		dirs.push_back(execname().parent_path().parent_path() / shareDir);
		// Adding relative path for running from sources
		dirs.push_back(execname().parent_path().parent_path() / "data");
		dirs.push_back(execname().parent_path().parent_path());
		dirs.push_back(execname().parent_path() / "data");
		dirs.push_back(execname().parent_path());
		#ifndef _WIN32
		// Adding XDG_DATA_DIRS
		{
			char const* xdg_data_dirs = getenv("XDG_DATA_DIRS");
			std::istringstream iss(xdg_data_dirs ? xdg_data_dirs : "/usr/local/share/:/usr/share/");
			for (std::string p; std::getline(iss, p, ':'); dirs.push_back(p / shortDir)) {}
		}
		#endif
		// TODO: Adding path from config file

		// Loop through the paths and pick the first one that contain some data
		for (Paths::const_iterator p = dirs.begin(); p != dirs.end(); ++p) {
			// Data dir
			if (fs::exists(*p / "hud")) game_data_dir = p->string();
			// Config dir
			if (fs::exists(*p / "config"))
				game_config_dir = (*p / "config").string();
			// Check if both are found
			if (!game_data_dir.empty() && !game_config_dir.empty()) break;
		}
	}

	// Find cache dir
	#ifdef _WIN32
	cache_dir = user_config_dir + "/cache";  // APPDATA/stuntrally/cache
	#else
	char const* xdg_cache_home = getenv("XDG_CACHE_HOME");
	cache_dir = (xdg_cache_home ? xdg_cache_home / shortDir : fs::path(home_dir) / ".cache" / shortDir).string();
	#endif
	// Create cache dir
	CreateDir(cache_dir, error_output);
	CreateDir(GetShaderCacheDir(), error_output);

	// Print diagnostic info
	std::stringstream out;
	out << "--- Directories: ---" << ogre_plugin_dir << std::endl;
	out << "Ogre plugin:  " << ogre_plugin_dir << std::endl;
	out << "Home:         " << home_dir << std::endl;
	out << "Default cfg:  " << GetGameConfigDir() << std::endl;
	out << "User cfg:     " << GetUserConfigDir() << std::endl;
	out << "Data:         " << GetDataPath() << std::endl;
	out << "User data:    " << GetUserDataDir() << std::endl;
	out << "Cache:        " << GetCacheDir() << std::endl;
	out << "Shader cache: " << GetShaderCacheDir() << std::endl;
	out << "Log:          " << GetLogDir() << std::endl;
	info_output << out.str();
}
Exemple #2
0
void render_window()
{
    game_config = GetGameConfig();
    game_levels = GetGameLevels();
    game_levels_count = GetGameLevelsCount();

    arguments = GetArguments();
    user_set = GetUserSettings();
    int start_level = get_start_level();

    save_dir_full = GetSaveDir();
    cache_dir_full = GetCacheDir();
    can_cache = (save_dir_full && cache_dir_full);

//------------------------------------------------------------------------------
    ApplyArguments();

    const SDL_VideoInfo *video_info = SDL_GetVideoInfo();
    if (user_set->geom_x > 0 && user_set->geom_y > 0)
    {
        disp_x = user_set->geom_x;
        disp_y = user_set->geom_y;
    }
    else
    {
        disp_x = video_info->current_w;
        disp_y = video_info->current_h;
    }

    int probe_bpp = (user_set->bpp == 0 ? video_info->vfmt->BitsPerPixel : user_set->bpp);
    disp_bpp = (probe_bpp == 32 ? probe_bpp : 16);

    bool rot = TransformGeom();

//------------------------------------------------------------------------------
#define BTN_SPACE_KOEF 4.5
    int btn_side = disp_y / 7;
    int btn_space = btn_side / BTN_SPACE_KOEF;
    int btns_padded_width = btn_side * 4 + btn_space * 5;
    if (btns_padded_width > disp_x)
    {
        //btn_side = ( wnd_w - 5 * ( btn_side / BTN_SPACE_KOEF ) ) / 4
        btn_side = (int)(disp_x / (4 + 5 / BTN_SPACE_KOEF));
        btn_space = btn_side / BTN_SPACE_KOEF;
    }
    int btns_width = btn_side * 4 + btn_space * 3;
    int font_height = btn_side / 3;
    int font_padding = font_height / 2;

//-- font and labels -----------------------------------------------------------
    TTF_Font *font = TTF_OpenFont(DEFAULT_FONT_FILE, font_height);
    if (!font)
    {
        log_error("Can't load font '%s'. Exiting.", DEFAULT_FONT_FILE);
        return;
    }

    SDL_Surface *levelTextSurface = NULL;
    SDL_Rect levelTextLocation;
    levelTextLocation.y = font_padding;

    SDL_Color fontColor = {0};
#ifndef RGBSWAP
    fontColor.r = 231;
    fontColor.g = 190;
    fontColor.b = 114;
#else
    //--enable-rgb-swap
    fontColor.r = 114;
    fontColor.g = 190;
    fontColor.b = 231;
#endif

    /* Window initialization */
    ingame = true;
    Uint32 sdl_flags = SDL_SWSURFACE;
    if (user_set->fullscreen_mode != FULLSCREEN_NONE)
        sdl_flags |= SDL_FULLSCREEN;
    SDL_Surface *disp = SDL_SetVideoMode(disp_x, disp_y, disp_bpp, sdl_flags);
    if (disp == NULL)
    {
        log_error("Can't set video mode %dx%dx%dbpp. Exiting.", disp_x, disp_y, disp_bpp);
        return;
    }
    screen = disp;
    SDL_Surface *gui_surface = disp;
    SDL_WM_SetCaption("Mokomaze", "Mokomaze");

    /* Draw loading screen */
    SDL_Color whiteColor = {0};
    whiteColor.r = whiteColor.g = whiteColor.b = 255;
    SDL_Surface *titleSurface = TTF_RenderText_Blended(font, "Loading...", whiteColor);
    SDL_Rect title_rect;
    title_rect.x = (disp_x - titleSurface->w) / 2;
    title_rect.y = (disp_y - titleSurface->h) / 2;
    title_rect.w = titleSurface->w;
    title_rect.h = titleSurface->h;
    SDL_BlitSurface(titleSurface, NULL, screen, &title_rect);
    SDL_UpdateRect(screen, title_rect.x, title_rect.y, title_rect.w, title_rect.h);
    SDL_FreeSurface(titleSurface);

//-- load pictures -------------------------------------------------------------
    SDL_Surface *back_pic     = LoadSvg(MDIR "prev-main.svg", btn_side, btn_side, false, false);
    SDL_Surface *forward_pic  = LoadSvg(MDIR "next-main.svg", btn_side, btn_side, false, false);
    SDL_Surface *settings_pic = LoadSvg(MDIR "settings-main.svg", btn_side, btn_side, false, false);
    SDL_Surface *exit_pic     = LoadSvg(MDIR "close-main.svg", btn_side, btn_side, false, false);

    SDL_Surface *back_i_pic    = LoadSvg(MDIR "prev-grey.svg", btn_side, btn_side, false, false);
    SDL_Surface *forward_i_pic = LoadSvg(MDIR "next-grey.svg", btn_side, btn_side, false, false);

    SDL_Surface *back_p_pic    = LoadSvg(MDIR "prev-light.svg", btn_side, btn_side, false, false);
    SDL_Surface *forward_p_pic = LoadSvg(MDIR "next-light.svg", btn_side, btn_side, false, false);

    int tmpx = (rot ? game_config.wnd_h : game_config.wnd_w);
    int tmpy = (rot ? game_config.wnd_w : game_config.wnd_h);
    desk_pic = LoadSvg(MDIR "desk.svg", tmpx, tmpy, rot, true);
    wall_pic = LoadSvg(MDIR "wall.svg", tmpx, tmpy, rot, true);
    int hole_d = game_config.hole_r * 2;
    fin_pic = LoadSvg(MDIR "openmoko.svg", hole_d, hole_d, rot, false);

    if (LoadImgErrors > 0)
    {
        log_error("Some images were not loaded. Exiting.");
        return;
    }

//-- positions of buttons ------------------------------------------------------
    SDL_Rect gui_rect_1, gui_rect_2, gui_rect_3, gui_rect_4;
    gui_rect_1.y = gui_rect_2.y = gui_rect_3.y = gui_rect_4.y = levelTextLocation.y + font_height + font_padding;
    gui_rect_1.x = (disp_x - btns_width) / 2;
    gui_rect_2.x = gui_rect_1.x + btn_side + btn_space;
    gui_rect_3.x = gui_rect_2.x + btn_side + btn_space;
    gui_rect_4.x = gui_rect_3.x + btn_side + btn_space;
//-- for click detection -------------------------------------------------------
    Box gui_box_1, gui_box_2, gui_box_3, gui_box_4;
    gui_box_1.x1 = gui_rect_1.x;
    gui_box_1.y1 = gui_rect_1.y;
    gui_box_1.x2 = gui_rect_1.x + btn_side;
    gui_box_1.y2 = gui_rect_1.y + btn_side;
    gui_box_2.x1 = gui_rect_2.x;
    gui_box_2.y1 = gui_rect_2.y;
    gui_box_2.x2 = gui_rect_2.x + btn_side;
    gui_box_2.y2 = gui_rect_2.y + btn_side;
    gui_box_3.x1 = gui_rect_3.x;
    gui_box_3.y1 = gui_rect_3.y;
    gui_box_3.x2 = gui_rect_3.x + btn_side;
    gui_box_3.y2 = gui_rect_3.y + btn_side;
    gui_box_4.x1 = gui_rect_4.x;
    gui_box_4.y1 = gui_rect_4.y;
    gui_box_4.x2 = gui_rect_4.x + btn_side;
    gui_box_4.y2 = gui_rect_4.y + btn_side;

    //create surface for rendering the level
    render_pic = CreateSurface(SDL_SWSURFACE, game_config.wnd_w, game_config.wnd_h, disp);

    if (user_set->scrolling)
        screen = CreateSurface(SDL_SWSURFACE, game_config.wnd_w, game_config.wnd_h, disp);

    if (user_set->fullscreen_mode != FULLSCREEN_NONE)
        SDL_ShowCursor(!ingame);

    desk_rect.x = 0;
    desk_rect.y = 0;
    desk_rect.w = game_config.wnd_w;
    desk_rect.h = game_config.wnd_h;

    SDL_Rect ball_rect;

    int disp_scroll_border = min(disp_x, disp_y) * 0.27;
    SDL_Rect screen_rect;
    screen_rect.x = 0;
    screen_rect.y = 0;
    screen_rect.w = disp_x;
    screen_rect.h = disp_y;
    SDL_Rect disp_rect;
    disp_rect = screen_rect;

    SDL_Color ballColor = {0};
    ballColor.r = 255;
    ballColor.g = 127;
    ballColor.b = 0;

    User user_set_new = *user_set;
    bool video_set_modified = false;

    /* Settings window initialization */
    settings_init(disp, font_height, user_set, &user_set_new);

    /* Render initialization */
    InitRender();

    /* Input system initialization */
    input_get_dummy(&input);
    SetInput();

    /* Vibro system initialization */
    vibro_get_dummy(&vibro);
    SetVibro();

    /* MazeCore initialization */
    maze_init();
    maze_set_config(game_config);
    maze_set_vibro_callback(BumpVibrate);
    maze_set_levels_data(game_levels, game_levels_count);

    cur_level = start_level;
    RenderLevel();
    RedrawDesk();
    maze_set_level(cur_level);
    ResetPrevPos();

    SDL_Event event;
    bool done = false;
    bool redraw_all = true;
    bool ingame_changed = false;
    int prev_ticks = SDL_GetTicks();
    Point mouse = {0};

//== Game Loop =================================================================
    while (!done)
    {
        bool wasclick = false;
        bool show_settings = false;
        while (SDL_PollEvent(&event))
        {
            bool btndown = false;
            bool btnesc = false;
            if (event.type == SDL_QUIT)
            {
                done = true;
            }
            else if (event.type == SDL_ACTIVEEVENT)
            {
                int g = event.active.gain;
                int s = event.active.state;
                if (ingame && !g && ((s & SDL_APPINPUTFOCUS) || (s & SDL_APPACTIVE)))
                {
                    btndown = true;
                }
            }
            else if (event.type == SDL_MOUSEMOTION)
            {
                mouse.x = event.motion.x;
                mouse.y = event.motion.y;
            }
            else if (event.type == SDL_MOUSEBUTTONUP)
            {
                StopFastChange();
            }
            else if (event.type == SDL_MOUSEBUTTONDOWN)
            {
                btndown = true;
            }
            else if (event.type == SDL_KEYDOWN)
            {
                switch(event.key.keysym.sym)
                {
                case SDLK_q:
                case SDLK_ESCAPE:
                    btnesc = true;
                case SDLK_SPACE:
                case SDLK_p:
                case SDLK_PAUSE:
                    btndown = true;
                    break;
                default:
                    break;
                }
            }
            else if (event.type == SDL_KEYUP)
            {
                switch(event.key.keysym.sym)
                {
                case SDLK_q:
                case SDLK_ESCAPE:
                    if( !wasclick || ingame || show_settings )
                        StopFastChange();
                    else
                        done = true;
                    break;
                case SDLK_SPACE:
                case SDLK_p:
                case SDLK_PAUSE:
                    StopFastChange();
                    break;
                default:
                    break;
                }
            }

            if (btndown)
            {
                if (!ingame)
                {
                    if (inbox(mouse.x, mouse.y, gui_box_1) && !btnesc)
                    {
                        if (cur_level > 0)
                        {
                            SDL_BlitSurface(back_p_pic, NULL, gui_surface, &gui_rect_1);
                            SDL_UpdateRect(gui_surface, gui_rect_1.x, gui_rect_1.y, gui_rect_1.w, gui_rect_1.h);

                            ChangeLevel(cur_level-1, &redraw_all, &wasclick);

                            fastchange_step = -10;
                            StopFastChange();
                            fastchange_timer = SDL_AddTimer(FASTCHANGE_INTERVAL, fastchange_callback, NULL);
                        }
                        continue;
                    }
                    else if (inbox(mouse.x, mouse.y, gui_box_2) && !btnesc)
                    {
                        if (cur_level < game_levels_count - 1)
                        {
                            SDL_BlitSurface(forward_p_pic, NULL, gui_surface, &gui_rect_2);
                            SDL_UpdateRect(gui_surface, gui_rect_2.x, gui_rect_2.y, gui_rect_2.w, gui_rect_2.h);

                            ChangeLevel(cur_level+1, &redraw_all, &wasclick);

                            fastchange_step = +10;
                            StopFastChange();
                            fastchange_timer = SDL_AddTimer(FASTCHANGE_INTERVAL, fastchange_callback, NULL);
                        }
                        continue;
                    }
                    else if (inbox(mouse.x, mouse.y, gui_box_3) && !btnesc)
                    {
                        show_settings = true;
                        RedrawDesk();
                        redraw_all = true;
                        wasclick = true;
                        continue;
                    }
                    else if (inbox(mouse.x, mouse.y, gui_box_4) || btnesc)
                    {
                        done = true;
                        continue;
                    }
                }
                ingame_changed = true;
            } //if (btndown)
        }

        if (ingame_changed)
        {
            ingame = !ingame;
            if (!ingame)
            {
                wasclick = true;
            }
            else
            {
                RedrawDesk();
                redraw_all = true;
            }

            if (user_set->fullscreen_mode == FULLSCREEN_INGAME)
                SDL_WM_ToggleFullScreen(disp);
            if (user_set->fullscreen_mode != FULLSCREEN_NONE)
                SDL_ShowCursor(!ingame);

            prev_ticks = SDL_GetTicks();
            ingame_changed = false;
        }

        if ((!ingame) && (!wasclick) && (must_fastchange))
        {
            int new_cur_level = cur_level + fastchange_dostep;
            clamp_max(new_cur_level, game_levels_count - 1);
            clamp_min(new_cur_level, 0);

            if (new_cur_level != cur_level)
            {
                if (fastchange_dostep < 0)
                {
                    SDL_BlitSurface(back_p_pic, NULL, gui_surface, &gui_rect_1);
                    SDL_UpdateRect(gui_surface, gui_rect_1.x, gui_rect_1.y, gui_rect_1.w, gui_rect_1.h);
                }
                else
                {
                    SDL_BlitSurface(forward_p_pic, NULL, gui_surface, &gui_rect_2);
                    SDL_UpdateRect(gui_surface, gui_rect_2.x, gui_rect_2.y, gui_rect_2.w, gui_rect_2.h);
                }

                ChangeLevel(new_cur_level, &redraw_all, &wasclick);
            }
            must_fastchange = false;
        }

        if (!ingame && !wasclick)
        {
            SDL_Delay(user_set->frame_delay);
            continue;
        }

//-- physics step --------------------------------------------------------------
        int ticks = SDL_GetTicks();
        int delta_ticks = ticks - prev_ticks;
        prev_ticks = ticks;
        clamp_min(delta_ticks, 1);
        clamp_max(delta_ticks, 1000 / 15);

        float acx = 0, acy = 0;
        input.read(&acx, &acy, NULL);
        if (input_cal_cycle)
            input_cal_cycle = (input_calibration_sample(&user_set->input_calibration_data, &acx, &acy, NULL) < MAX_CALIBRATION_SAMPLES);
        input_calibration_adjust(&user_set->input_calibration_data, &acx, &acy, NULL);
        maze_set_speed(user_set->ball_speed);
        maze_set_tilt(acx, acy, 0);
        GameState game_state = maze_step(delta_ticks);

        const dReal *R;
        int tk_px, tk_py, tk_pz;
        maze_get_ball(&tk_px, &tk_py, &tk_pz, &R);
        maze_get_animations(&keys_anim, &final_anim);
//------------------------------------------------------------------------------

        //restore the background
        ball_rect.w = game_config.ball_r * 2;
        ball_rect.h = game_config.ball_r * 2; //
        ball_rect.x = prev_px - game_config.ball_r;
        ball_rect.y = prev_py - game_config.ball_r;
        SDL_BlitSurface(render_pic, &ball_rect, screen, &ball_rect);

        UpdateBufAnimation();
        DrawBall(tk_px, tk_py, tk_pz, R, ballColor);

        //update the screen
        if (!redraw_all && !user_set->scrolling)
        {
            int min_px, max_px;
            int min_py, max_py;
            if (prev_px <= tk_px)
            {
                min_px = prev_px;
                max_px = tk_px;
            }
            else
            {
                min_px = tk_px;
                max_px = prev_px;
            }

            if (prev_py <= tk_py)
            {
                min_py = prev_py;
                max_py = tk_py;
            }
            else
            {
                min_py = tk_py;
                max_py = prev_py;
            }
            min_px -= game_config.ball_r;
            max_px += game_config.ball_r;
            min_py -= game_config.ball_r;
            max_py += game_config.ball_r;
            clamp_min(min_px, 0);
            clamp_max(max_px, game_config.wnd_w - 1);
            clamp_min(min_py, 0);
            clamp_max(max_py, game_config.wnd_h - 1);
            SDL_UpdateRect(screen, min_px, min_py, max_px - min_px, max_py - min_py);
            UpdateScreenAnimation();
        }

        if (user_set->scrolling)
        {
            clamp_min(screen_rect.x, tk_px - disp_x + disp_scroll_border);
            clamp_max(screen_rect.x, tk_px - disp_scroll_border);
            clamp_min(screen_rect.y, tk_py - disp_y + disp_scroll_border);
            clamp_max(screen_rect.y, tk_py - disp_scroll_border);
            clamp(screen_rect.x, 0, game_config.wnd_w - disp_x);
            clamp(screen_rect.y, 0, game_config.wnd_h - disp_y);
            SDL_BlitSurface(screen, &screen_rect, disp, &disp_rect);
        }

        prev_px = tk_px;
        prev_py = tk_py;

//-- GUI -----------------------------------------------------------------------
        if (wasclick && !ingame && !show_settings)
        {
            char txt[32];
            sprintf(txt, "Level %d/%d", cur_level + 1, game_levels_count);
            SDL_FreeSurface(levelTextSurface);
            levelTextSurface = TTF_RenderText_Blended(font, txt, fontColor);
            levelTextLocation.x = (disp_x - levelTextSurface->w) / 2;
            SDL_BlitSurface(levelTextSurface, NULL, gui_surface, &levelTextLocation);

            if (cur_level > 0)
                SDL_BlitSurface(back_pic, NULL, gui_surface, &gui_rect_1);
            else
                SDL_BlitSurface(back_i_pic, NULL, gui_surface, &gui_rect_1);

            if (cur_level < game_levels_count - 1)
                SDL_BlitSurface(forward_pic, NULL, gui_surface, &gui_rect_2);
            else
                SDL_BlitSurface(forward_i_pic, NULL, gui_surface, &gui_rect_2);

            SDL_BlitSurface(settings_pic, NULL, gui_surface, &gui_rect_3);
            SDL_BlitSurface(exit_pic, NULL, gui_surface, &gui_rect_4);
            redraw_all = true;
        }
//------------------------------------------------------------------------------

        //update the whole screen if needed
        if (user_set->scrolling)
        {
            SDL_Flip(disp);
        }
        else if (redraw_all)
        {
            SDL_Flip(screen);
        }
        redraw_all = false;

        if (show_settings)
        {
            bool _video_set_modified = false;
            bool _input_set_modified = false;
            bool _vibro_set_modified = false;
            settings_show(&input_cal_cycle, &_video_set_modified, &_input_set_modified, &_vibro_set_modified);
            if (input_cal_cycle)
                input_calibration_reset();
            if (_video_set_modified)
                video_set_modified = true;
            if (_input_set_modified)
                SetInput();
            if (_vibro_set_modified)
                SetVibro();
            SDL_GetMouseState(&mouse.x, &mouse.y);
            ingame_changed = true;
        }

        switch (game_state)
        {
        case GAME_STATE_FAILED:
            RedrawDesk();
            maze_restart_level();
            ResetPrevPos();
            redraw_all = true;
            break;
        case GAME_STATE_SAVED:
            RedrawDesk();
            maze_reload_level();
            ResetPrevPos();
            redraw_all = true;
            break;
        case GAME_STATE_WIN:
            if (++cur_level >= game_levels_count) cur_level=0;
            RenderLevel();
            RedrawDesk();
            maze_set_level(cur_level);
            ResetPrevPos();
            redraw_all = true;
            break;
        default:
            break;
        }

        SDL_Delay(user_set->frame_delay);
    }
//==============================================================================

    if (video_set_modified)
    {
        user_set->scrolling = user_set_new.scrolling;
        user_set->geom_x = user_set_new.geom_x;
        user_set->geom_y = user_set_new.geom_y;
        user_set->bpp = user_set_new.bpp;
        user_set->fullscreen_mode = user_set_new.fullscreen_mode;
        user_set->frame_delay = user_set_new.frame_delay;
    }

    user_set->level = cur_level + 1;
    SaveUserSettings();

    settings_shutdown();

    SDL_FreeSurface(levelTextSurface);
    TTF_CloseFont(font);
    vibro.shutdown();
    input.shutdown();
}