#include "options.h" #include // Para SDL_WINDOW_FULLSCREEN_DESKTOP #include // Para find_if #include // Para isspace #include // Para basic_ostream, operator<<, basic_ofstream #include // Para function #include // Para cout, cerr #include // Para basic_istringstream #include // Para char_traits, string, operator<<, hash #include // Para unordered_map, operator==, _Node_const_i... #include // Para pair // Variables Options options; bool setOptions(const std::string& var, const std::string& value); // Crea e inicializa las opciones del programa void initOptions() { options = Options(); #ifdef DEBUG options.section = SectionState(Section::ENDING2, Subsection::LOGO_TO_INTRO); options.console = true; #else options.section = SectionState(Section::LOGO, Subsection::LOGO_TO_INTRO); options.console = false; #endif } // Carga las opciones desde un fichero bool loadOptionsFromFile(const std::string& file_path) { // Indicador de éxito en la carga bool success = true; // Versión actual del fichero const std::string configVersion = options.version; options.version = ""; // Variables para manejar el fichero std::ifstream file(file_path); // Si el fichero se puede abrir if (file.good()) { // Procesa el fichero línea a línea if (options.console) { std::cout << "Reading file config.txt\n"; } std::string line; while (std::getline(file, line)) { // Elimina espacios en blanco iniciales y finales line = std::string(std::find_if(line.begin(), line.end(), [](int ch) { return !std::isspace(ch); }), line.end()); line.erase(std::find_if(line.rbegin(), line.rend(), [](int ch) { return !std::isspace(ch); }) .base(), line.end()); // Ignora líneas vacías o comentarios if (line.empty() || line[0] == '#') { continue; } // Usa un stringstream para dividir la línea en dos partes std::istringstream iss(line); std::string key, value; if (iss >> key >> value) { if (!setOptions(key, value)) { if (options.console) { std::cout << "Warning: file config.txt\n"; std::cout << "unknown parameter " << key << std::endl; } success = false; } } } // Cierra el fichero if (options.console) { std::cout << "Closing file config.txt\n\n"; } file.close(); } else { // Crea el fichero con los valores por defecto saveOptionsToFile(file_path); } // Si la versión de fichero no coincide, crea un fichero nuevo con los valores por defecto if (configVersion != options.version) { initOptions(); saveOptionsToFile(file_path); if (options.console) { std::cout << "Wrong config file: initializing options.\n\n"; } } return success; } // Guarda las opciones en un fichero bool saveOptionsToFile(const std::string& file_path) { // Crea y abre el fichero de texto std::ofstream file(file_path); bool success = file.is_open(); // Verifica si el archivo se abrió correctamente if (!success) // Si no se pudo abrir el archivo, muestra un mensaje de error y devuelve false { if (options.console) { std::cerr << "Error: Unable to open file " << file_path << " for writing." << std::endl; } return false; } if (options.console) { std::cout << file_path << " open for writing" << std::endl; } // Escribe en el fichero file << "# Versión de la configuración\n"; file << "version " << options.version << "\n"; file << "\n## CONTROL\n"; file << "# Esquema de control: 0 = Cursores, 1 = OPQ, 2 = WAD\n"; file << "keys " << static_cast(options.keys) << "\n"; file << "\n## WINDOW\n"; file << "# Zoom de la ventana: 1 = Normal, 2 = Doble, 3 = Triple, ...\n"; file << "window.zoom " << options.window.zoom << "\n"; file << "\n## VIDEO\n"; file << "# Modo de video: 0 = Ventana, 1 = Pantalla completa, 2 = Pantalla completa (escritorio)\n"; file << "video.mode " << options.video.mode << "\n\n"; file << "# Filtro de pantalla: 0 = Nearest, 1 = Linear\n"; file << "video.filter " << static_cast(options.video.filter) << "\n\n"; file << "# Shaders: 1 = Activado, 0 = Desactivado\n"; file << "video.shaders " << boolToString(options.video.shaders) << "\n\n"; file << "# Sincronización vertical: 1 = Activado, 0 = Desactivado\n"; file << "video.vertical_sync " << boolToString(options.video.vertical_sync) << "\n\n"; file << "# Escalado entero: 1 = Activado, 0 = Desactivado\n"; file << "video.integer_scale " << boolToString(options.video.integer_scale) << "\n\n"; file << "# Mantener aspecto: 1 = Activado, 0 = Desactivado\n"; file << "video.keep_aspect " << boolToString(options.video.keep_aspect) << "\n\n"; file << "# Borde: 1 = Activado, 0 = Desactivado\n"; file << "video.border.enabled " << boolToString(options.video.border.enabled) << "\n\n"; file << "# Ancho del borde\n"; file << "video.border.width " << options.video.border.width << "\n\n"; file << "# Alto del borde\n"; file << "video.border.height " << options.video.border.height << "\n\n"; file << "# Paleta\n"; file << "video.palette " << options.video.palette << "\n"; // Cierra el fichero file.close(); return success; } bool setOptions(const std::string& var, const std::string& value) { static const std::unordered_map> optionHandlers = { {"version", [](const std::string& v) { options.version = v; }}, {"keys", [](const std::string& v) { int val = safeStoi(v, static_cast(DEFAULT_CONTROL_SCHEME)); if (val == static_cast(ControlScheme::CURSOR) || val == static_cast(ControlScheme::OPQA) || val == static_cast(ControlScheme::WASD)) { options.keys = static_cast(val); } else { options.keys = DEFAULT_CONTROL_SCHEME; } }}, {"window.zoom", [](const std::string& v) { int val = safeStoi(v, DEFAULT_WINDOW_ZOOM); if (val > 0) { options.window.zoom = val; } else { options.window.zoom = DEFAULT_WINDOW_ZOOM; } }}, {"video.mode", [](const std::string& v) { int val = safeStoi(v, 0); if (val == 0 || val == SDL_WINDOW_FULLSCREEN_DESKTOP) { options.video.mode = val; } else { options.video.mode = 0; } }}, {"video.filter", [](const std::string& v) { int val = safeStoi(v, static_cast(DEFAULT_VIDEO_FILTER)); if (val == static_cast(ScreenFilter::NEAREST) || val == static_cast(ScreenFilter::LINEAR)) { options.video.filter = static_cast(val); } else { options.video.filter = DEFAULT_VIDEO_FILTER; } }}, {"video.shaders", [](const std::string& v) { options.video.shaders = stringToBool(v); }}, {"video.vertical_sync", [](const std::string& v) { options.video.vertical_sync = stringToBool(v); }}, {"video.integer_scale", [](const std::string& v) { options.video.integer_scale = stringToBool(v); }}, {"video.keep_aspect", [](const std::string& v) { options.video.keep_aspect = stringToBool(v); }}, {"video.border.enabled", [](const std::string& v) { options.video.border.enabled = stringToBool(v); }}, {"video.border.width", [](const std::string& v) { int val = safeStoi(v, DEFAULT_BORDER_WIDTH); if (val > 0) { options.video.border.width = val; } else { options.video.border.width = DEFAULT_BORDER_WIDTH; } }}, {"video.border.height", [](const std::string& v) { int val = safeStoi(v, DEFAULT_BORDER_HEIGHT); if (val > 0) { options.video.border.height = val; } else { options.video.border.height = DEFAULT_BORDER_HEIGHT; } }}, {"video.palette", [](const std::string& v) { options.video.palette = v; }}}; auto it = optionHandlers.find(var); if (it != optionHandlers.end()) { it->second(value); return true; } return false; }