#include "options.h" #include // Para SDL_LogCategory, SDL_LogInfo, SDL_LogError #include // Para clamp #include // Para basic_ostream, operator<<, basic_ostream::... #include // Para swap #include // Para vector #include "input.h" // Para InputDeviceToUse #include "lang.h" // Para Code #include "utils.h" // Para boolToString, stringToBool, getFileName // Variables Options options; // Declaraciones bool setOptions(const std::string &var, const std::string &value); // Inicializa las opciones del programa void initOptions() { options.window.caption = "Coffee Crisis Arcade Edition"; options.window.size = 2; // Opciones de video options.video.fullscreen = false; options.video.scale_mode = SDL_ScaleMode::SDL_SCALEMODE_NEAREST; options.video.v_sync = true; options.video.integer_scale = true; options.video.shaders = false; // Opciones de audio options.audio.enabled = true; options.audio.volume = 100; options.audio.music.enabled = true; options.audio.music.volume = 100; options.audio.sound.enabled = true; options.audio.sound.volume = 50; // Opciones de juego options.game.difficulty = GameDifficulty::NORMAL; options.game.language = lang::Code::VALENCIAN; options.game.autofire = true; options.game.clear_last_hi_score_entries(); // Opciones de control options.controllers.clear(); options.controllers.resize(2); options.controllers.at(0).player_id = 1; options.controllers.at(1).player_id = 2; setKeyboardToPlayer(1); // Opciones pendientes options.pending_changes.new_language = options.game.language; options.pending_changes.new_difficulty = options.game.difficulty; options.pending_changes.has_pending_changes = false; } // Carga el fichero de configuración bool loadOptionsFile(std::string file_path) { // Inicializa las opciones del programa initOptions(); // Indicador de éxito en la carga bool success = true; // 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 SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str()); std::string line; while (std::getline(file, line)) { // Comprueba que la línea no sea un comentario if (line.substr(0, 1) != "#") { // Encuentra la posición del carácter '=' int pos = line.find("="); // Procesa las dos subcadenas if (!setOptions(line.substr(0, pos), line.substr(pos + 1, line.length()))) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str()); success = false; } } } file.close(); } // El fichero no existe else { // Crea el fichero con los valores por defecto saveOptionsFile(file_path); } // Normaliza los valores if (options.game.language != lang::Code::ENGLISH && options.game.language != lang::Code::VALENCIAN && options.game.language != lang::Code::SPANISH) { options.game.language = lang::Code::ENGLISH; } return success; } // Guarda el fichero de configuración bool saveOptionsFile(std::string file_path) { std::ofstream file(file_path); if (!file.good()) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: %s can't be opened", getFileName(file_path).c_str()); return false; } SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file: %s", getFileName(file_path).c_str()); applyPendingChanges(); // Opciones de video file << "## VIDEO\n"; file << "## video.scale_mode [" << static_cast(SDL_ScaleMode::SDL_SCALEMODE_NEAREST) << ": nearest, " << static_cast(SDL_ScaleMode::SDL_SCALEMODE_LINEAR) << ": lineal]\n"; file << "\n"; file << "window.zoom=" << options.window.size << "\n"; file << "video.fullscreen=" << boolToString(options.video.fullscreen) << "\n"; file << "video.scale_mode=" << static_cast(options.video.scale_mode) << "\n"; file << "video.v_sync=" << boolToString(options.video.v_sync) << "\n"; file << "video.integer_scale=" << boolToString(options.video.integer_scale) << "\n"; file << "video.shaders=" << boolToString(options.video.shaders) << "\n"; // Opciones de audio file << "\n\n## AUDIO\n"; file << "## volume [0 .. 100]\n"; file << "\n"; file << "audio.enabled=" << boolToString(options.audio.enabled) << "\n"; file << "audio.volume=" << options.audio.volume << "\n"; file << "audio.music.enabled=" << boolToString(options.audio.music.enabled) << "\n"; file << "audio.music.volume=" << options.audio.music.volume << "\n"; file << "audio.sound.enabled=" << boolToString(options.audio.sound.enabled) << "\n"; file << "audio.sound.volume=" << options.audio.sound.volume << "\n"; // Opciones del juego file << "\n\n## GAME\n"; file << "## game.language [0: spanish, 1: valencian, 2: english]\n"; file << "## game.difficulty [" << static_cast(GameDifficulty::EASY) << ": easy, " << static_cast(GameDifficulty::NORMAL) << ": normal, " << static_cast(GameDifficulty::HARD) << ": hard]\n"; file << "\n"; file << "game.language=" << static_cast(options.game.language) << "\n"; file << "game.difficulty=" << static_cast(options.game.difficulty) << "\n"; file << "game.autofire=" << boolToString(options.game.autofire) << "\n"; // Opciones de mandos file << "\n\n## CONTROLLERS\n"; int controller_index = 0; for (const auto &controller : options.controllers) { file << "\n"; file << "controller." << controller_index << ".name=" << controller.name << "\n"; file << "controller." << controller_index << ".player=" << controller.player_id << "\n"; file << "controller." << controller_index << ".type=" << static_cast(controller.type) << "\n"; file << "controller." << controller_index << ".button.fire_left=" << controller.buttons.at(0) << "\n"; file << "controller." << controller_index << ".button.fire_center=" << controller.buttons.at(1) << "\n"; file << "controller." << controller_index << ".button.fire_right=" << controller.buttons.at(2) << "\n"; file << "controller." << controller_index << ".button.start=" << controller.buttons.at(3) << "\n"; file << "controller." << controller_index << ".button.service=" << controller.buttons.at(4) << "\n"; // Incrementa el índice ++controller_index; } // Cierra el fichero file.close(); return true; } // Asigna variables a partir de dos cadenas bool setOptions(const std::string &var, const std::string &value) { // Indicador de éxito en la asignación auto success = true; // Opciones de video if (var == "video.fullscreen") { options.video.fullscreen = stringToBool(value); } else if (var == "window.zoom") { options.window.size = std::stoi(value); } else if (var == "video.scale_mode") { options.video.scale_mode = static_cast(std::stoi(value)); } else if (var == "video.shaders") { options.video.shaders = stringToBool(value); } else if (var == "video.integer_scale") { options.video.integer_scale = stringToBool(value); } else if (var == "video.v_sync") { options.video.v_sync = stringToBool(value); } // Opciones de audio else if (var == "audio.enabled") { options.audio.enabled = stringToBool(value); } else if (var == "audio.volume") { options.audio.volume = std::clamp(std::stoi(value), 0, 100); } else if (var == "audio.music.enabled") { options.audio.music.enabled = stringToBool(value); } else if (var == "audio.music.volume") { options.audio.music.volume = std::clamp(std::stoi(value), 0, 100); } else if (var == "audio.sound.enabled") { options.audio.sound.enabled = stringToBool(value); } else if (var == "audio.sound.volume") { options.audio.sound.volume = std::clamp(std::stoi(value), 0, 100); } // Opciones de juego else if (var == "game.language") { options.game.language = static_cast(std::stoi(value)); options.pending_changes.new_language = options.game.language; } else if (var == "game.difficulty") { options.game.difficulty = static_cast(std::stoi(value)); options.pending_changes.new_difficulty = options.game.difficulty; } else if (var == "game.autofire") { options.game.autofire = stringToBool(value); } // Opciones de mandos else if (var == "controller.0.name") { options.controllers.at(0).name = value; } else if (var == "controller.0.player") { options.controllers.at(0).player_id = std::clamp(std::stoi(value), 1, 2); } else if (var == "controller.0.type") { options.controllers.at(0).type = static_cast(std::stoi(value)); } else if (var == "controller.0.button.fire_left") { options.controllers.at(0).buttons.at(0) = static_cast(std::stoi(value)); } else if (var == "controller.0.button.fire_center") { options.controllers.at(0).buttons.at(1) = static_cast(std::stoi(value)); } else if (var == "controller.0.button.fire_right") { options.controllers.at(0).buttons.at(2) = static_cast(std::stoi(value)); } else if (var == "controller.0.button.start") { options.controllers.at(0).buttons.at(3) = static_cast(std::stoi(value)); } else if (var == "controller.0.button.service") { options.controllers.at(0).buttons.at(4) = static_cast(std::stoi(value)); } else if (var == "controller.1.name") { options.controllers.at(1).name = value; } else if (var == "controller.1.player") { options.controllers.at(1).player_id = std::clamp(std::stoi(value), 1, 2); } else if (var == "controller.1.type") { options.controllers.at(1).type = static_cast(std::stoi(value)); } else if (var == "controller.1.button.fire_left") { options.controllers.at(1).buttons.at(0) = static_cast(std::stoi(value)); } else if (var == "controller.1.button.fire_center") { options.controllers.at(1).buttons.at(1) = static_cast(std::stoi(value)); } else if (var == "controller.1.button.fire_right") { options.controllers.at(1).buttons.at(2) = static_cast(std::stoi(value)); } else if (var == "controller.1.button.start") { options.controllers.at(1).buttons.at(3) = static_cast(std::stoi(value)); } else if (var == "controller.1.button.service") { options.controllers.at(1).buttons.at(4) = static_cast(std::stoi(value)); } // Lineas vacias o que empiezan por comentario else if (var.empty() || var.starts_with("#")) { } else { success = false; } return success; } // Asigna el teclado al jugador void setKeyboardToPlayer(int player_id) { for (auto &controller : options.controllers) { if (controller.player_id == player_id) { controller.type = InputDeviceToUse::ANY; } else { controller.type = InputDeviceToUse::CONTROLLER; } } } // Intercambia el teclado de jugador void swapOptionsKeyboard() { std::swap(options.controllers.at(0).type, options.controllers.at(1).type); } // Intercambia los jugadores asignados a los dos primeros mandos void swapOptionsControllers() { std::swap(options.controllers.at(0).player_id, options.controllers.at(1).player_id); std::swap(options.controllers.at(0).type, options.controllers.at(1).type); } // Averigua quien está usando el teclado int getPlayerWhoUsesKeyboard() { for (const auto &controller : options.controllers) { if (controller.type == InputDeviceToUse::ANY) { return controller.player_id; } } return 0; } // Aplica los cambios pendientes copiando los valores a sus variables void applyPendingChanges() { if (options.pending_changes.has_pending_changes) { options.game.language = options.pending_changes.new_language; options.game.difficulty = options.pending_changes.new_difficulty; options.pending_changes.has_pending_changes = false; } }