#include "param.h" #include // Para SDL_LogCategory, SDL_LogError, SDL_LogInfo #include // Para basic_istream, basic_ifstream, ifstream #include #include // Para basic_istringstream #include // Para runtime_error #include // Para operator==, stoi, char_traits, string, ope... #include #include "color.h" #include "ui/notifier.h" // Para Notifier::Position #include "utils.h" // Variable global - ahora se inicializa automáticamente con valores por defecto Param param; // Declaraciones de funciones privadas namespace { auto setParams(const std::string& var, const std::string& value) -> bool; } // Implementación del método privado de Param void Param::precalculateZones() { // playArea - cálculos basados en el rectángulo actual game.play_area.center_x = game.play_area.rect.w / 2; game.play_area.first_quarter_x = game.play_area.rect.w / 4; game.play_area.third_quarter_x = game.play_area.rect.w / 4 * 3; game.play_area.center_y = game.play_area.rect.h / 2; game.play_area.first_quarter_y = game.play_area.rect.h / 4; game.play_area.third_quarter_y = game.play_area.rect.h / 4 * 3; // gameArea - cálculos basados en width y height actuales game.game_area.rect = {.x = 0, .y = 0, .w = game.width, .h = game.height}; game.game_area.center_x = game.game_area.rect.w / 2; game.game_area.first_quarter_x = game.game_area.rect.w / 4; game.game_area.third_quarter_x = game.game_area.rect.w / 4 * 3; game.game_area.center_y = game.game_area.rect.h / 2; game.game_area.first_quarter_y = game.game_area.rect.h / 4; game.game_area.third_quarter_y = game.game_area.rect.h / 4 * 3; } // Carga los parámetros desde un archivo void loadParamsFromFile(const std::string& file_path) { // Los parámetros ya están inicializados con valores por defecto // Solo necesitamos abrir el archivo y sobrescribir los valores que aparezcan std::ifstream file(file_path); if (!file.is_open()) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo abrir el archivo %s", file_path.c_str()); throw std::runtime_error("No se pudo abrir el archivo: " + file_path); } SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str()); std::string line; std::string param_name; std::string param_value; while (std::getline(file, line)) { // Elimina comentarios auto comment_pos = line.find('#'); if (comment_pos != std::string::npos) { line.resize(comment_pos); } // Usa un stream para separar palabras std::istringstream iss(line); if (iss >> param_name >> param_value) { if (!setParams(param_name, param_value)) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param_name.c_str()); } } } file.close(); // Recalcula las zonas después de cargar todos los parámetros param.precalculateZones(); } // Implementación local de setParams namespace { auto setParams(const std::string& var, const std::string& value) -> bool { // Mapas estáticos para diferentes tipos de parámetros static const std::unordered_map> INT_PARAMS = { {"game.width", [](const std::string& v) { param.game.width = std::stoi(v); }}, {"game.height", [](const std::string& v) { param.game.height = std::stoi(v); }}, {"game.item_size", [](const std::string& v) { param.game.item_size = std::stoi(v); }}, {"game.play_area.rect.x", [](const std::string& v) { param.game.play_area.rect.x = std::stoi(v); }}, {"game.play_area.rect.y", [](const std::string& v) { param.game.play_area.rect.y = std::stoi(v); }}, {"game.play_area.rect.w", [](const std::string& v) { param.game.play_area.rect.w = std::stoi(v); }}, {"game.play_area.rect.h", [](const std::string& v) { param.game.play_area.rect.h = std::stoi(v); }}, {"game.name_entry_idle_time", [](const std::string& v) { param.game.name_entry_idle_time = std::stoi(v); }}, {"game.name_entry_total_time", [](const std::string& v) { param.game.name_entry_total_time = std::stoi(v); }}, {"game.hit_stop_ms", [](const std::string& v) { param.game.hit_stop_ms = std::stoi(v); }}, {"fade.num_squares_width", [](const std::string& v) { param.fade.num_squares_width = std::stoi(v); }}, {"fade.num_squares_height", [](const std::string& v) { param.fade.num_squares_height = std::stoi(v); }}, {"fade.random_squares_delay", [](const std::string& v) { param.fade.random_squares_delay = std::stoi(v); }}, {"fade.random_squares_mult", [](const std::string& v) { param.fade.random_squares_mult = std::stoi(v); }}, {"fade.post_duration", [](const std::string& v) { param.fade.post_duration = std::stoi(v); }}, {"fade.venetian_size", [](const std::string& v) { param.fade.venetian_size = std::stoi(v); }}, {"scoreboard.rect.x", [](const std::string& v) { param.scoreboard.rect.x = std::stoi(v); }}, {"scoreboard.rect.y", [](const std::string& v) { param.scoreboard.rect.y = std::stoi(v); }}, {"scoreboard.rect.w", [](const std::string& v) { param.scoreboard.rect.w = std::stoi(v); }}, {"scoreboard.rect.h", [](const std::string& v) { param.scoreboard.rect.h = std::stoi(v); }}, {"scoreboard.skip_countdown_value", [](const std::string& v) { param.scoreboard.skip_countdown_value = std::stoi(v); }}, {"title.press_start_position", [](const std::string& v) { param.title.press_start_position = std::stoi(v); }}, {"title.title_duration", [](const std::string& v) { param.title.title_duration = std::stoi(v); }}, {"title.arcade_edition_position", [](const std::string& v) { param.title.arcade_edition_position = std::stoi(v); }}, {"title.title_c_c_position", [](const std::string& v) { param.title.title_c_c_position = std::stoi(v); }}, {"intro.text_distance_from_bottom", [](const std::string& v) { param.intro.text_distance_from_bottom = std::stoi(v); }}}; static const std::unordered_map> COLOR_PARAMS = { {"fade.color", [](const std::string& v) { param.fade.color = Color::fromHex(v); }}, {"scoreboard.separator_color", [](const std::string& v) { param.scoreboard.separator_color = Color::fromHex(v); }}, {"scoreboard.easy_color", [](const std::string& v) { param.scoreboard.easy_color = Color::fromHex(v); }}, {"scoreboard.normal_color", [](const std::string& v) { param.scoreboard.normal_color = Color::fromHex(v); }}, {"scoreboard.hard_color", [](const std::string& v) { param.scoreboard.hard_color = Color::fromHex(v); }}, {"scoreboard.text_color1", [](const std::string& v) { param.scoreboard.text_color1 = Color::fromHex(v); }}, {"scoreboard.text_color2", [](const std::string& v) { param.scoreboard.text_color2 = Color::fromHex(v); }}, {"title.bg_color", [](const std::string& v) { param.title.bg_color = Color::fromHex(v); }}, {"background.attenuate_color", [](const std::string& v) { param.background.attenuate_color = Color::fromHex(v); }}, {"notification.color", [](const std::string& v) { param.notification.color = Color::fromHex(v); }}, {"service_menu.title_color", [](const std::string& v) { param.service_menu.title_color = Color::fromHex(v); }}, {"service_menu.text_color", [](const std::string& v) { param.service_menu.text_color = Color::fromHex(v); }}, {"service_menu.selected_color", [](const std::string& v) { param.service_menu.selected_color = Color::fromHex(v); }}, {"service_menu.bg_color", [](const std::string& v) { param.service_menu.bg_color = Color::fromHex(v); }}, {"service_menu.window_message.bg_color", [](const std::string& v) { param.service_menu.window_message.bg_color = Color::fromHex(v); }}, {"service_menu.window_message.border_color", [](const std::string& v) { param.service_menu.window_message.border_color = Color::fromHex(v); }}, {"service_menu.window_message.title_color", [](const std::string& v) { param.service_menu.window_message.title_color = Color::fromHex(v); }}, {"service_menu.window_message.text_color", [](const std::string& v) { param.service_menu.window_message.text_color = Color::fromHex(v); }}, {"intro.bg_color", [](const std::string& v) { param.intro.bg_color = Color::fromHex(v); }}, {"intro.card_color", [](const std::string& v) { param.intro.card_color = Color::fromHex(v); }}, {"intro.shadow_color", [](const std::string& v) { param.intro.shadow_color = Color::fromHex(v); }}, {"debug.color", [](const std::string& v) { param.debug.color = Color::fromHex(v); }}, {"resource.color", [](const std::string& v) { param.resource.color = Color::fromHex(v); }}, {"game.item_text_outline_color", [](const std::string& v) { param.game.item_text_outline_color = Color::fromHex(v); }}, {"player.default_shirt[0].darkest", [](const std::string& v) { param.player.default_shirt[0].darkest = Color::fromHex(v); }}, {"player.default_shirt[0].dark", [](const std::string& v) { param.player.default_shirt[0].dark = Color::fromHex(v); }}, {"player.default_shirt[0].base", [](const std::string& v) { param.player.default_shirt[0].base = Color::fromHex(v); }}, {"player.default_shirt[0].light", [](const std::string& v) { param.player.default_shirt[0].light = Color::fromHex(v); }}, {"player.default_shirt[1].darkest", [](const std::string& v) { param.player.default_shirt[1].darkest = Color::fromHex(v); }}, {"player.default_shirt[1].dark", [](const std::string& v) { param.player.default_shirt[1].dark = Color::fromHex(v); }}, {"player.default_shirt[1].base", [](const std::string& v) { param.player.default_shirt[1].base = Color::fromHex(v); }}, {"player.default_shirt[1].light", [](const std::string& v) { param.player.default_shirt[1].light = Color::fromHex(v); }}, {"player.one_coffee_shirt[0].darkest", [](const std::string& v) { param.player.one_coffee_shirt[0].darkest = Color::fromHex(v); }}, {"player.one_coffee_shirt[0].dark", [](const std::string& v) { param.player.one_coffee_shirt[0].dark = Color::fromHex(v); }}, {"player.one_coffee_shirt[0].base", [](const std::string& v) { param.player.one_coffee_shirt[0].base = Color::fromHex(v); }}, {"player.one_coffee_shirt[0].light", [](const std::string& v) { param.player.one_coffee_shirt[0].light = Color::fromHex(v); }}, {"player.one_coffee_shirt[1].darkest", [](const std::string& v) { param.player.one_coffee_shirt[1].darkest = Color::fromHex(v); }}, {"player.one_coffee_shirt[1].dark", [](const std::string& v) { param.player.one_coffee_shirt[1].dark = Color::fromHex(v); }}, {"player.one_coffee_shirt[1].base", [](const std::string& v) { param.player.one_coffee_shirt[1].base = Color::fromHex(v); }}, {"player.one_coffee_shirt[1].light", [](const std::string& v) { param.player.one_coffee_shirt[1].light = Color::fromHex(v); }}, {"player.two_coffee_shirt[0].darkest", [](const std::string& v) { param.player.two_coffee_shirt[0].darkest = Color::fromHex(v); }}, {"player.two_coffee_shirt[0].dark", [](const std::string& v) { param.player.two_coffee_shirt[0].dark = Color::fromHex(v); }}, {"player.two_coffee_shirt[0].base", [](const std::string& v) { param.player.two_coffee_shirt[0].base = Color::fromHex(v); }}, {"player.two_coffee_shirt[0].light", [](const std::string& v) { param.player.two_coffee_shirt[0].light = Color::fromHex(v); }}, {"player.two_coffee_shirt[1].darkest", [](const std::string& v) { param.player.two_coffee_shirt[1].darkest = Color::fromHex(v); }}, {"player.two_coffee_shirt[1].dark", [](const std::string& v) { param.player.two_coffee_shirt[1].dark = Color::fromHex(v); }}, {"player.two_coffee_shirt[1].base", [](const std::string& v) { param.player.two_coffee_shirt[1].base = Color::fromHex(v); }}, {"player.two_coffee_shirt[1].light", [](const std::string& v) { param.player.two_coffee_shirt[1].light = Color::fromHex(v); }}, {"player.outline_color[0]", [](const std::string& v) { param.player.outline_color[0] = Color::fromHex(v); }}, {"player.outline_color[1]", [](const std::string& v) { param.player.outline_color[1] = Color::fromHex(v); }}}; static const std::unordered_map> BOOL_PARAMS = { {"game.hit_stop", [](const std::string& v) { param.game.hit_stop = stringToBool(v); }}, {"scoreboard.separator_autocolor", [](const std::string& v) { param.scoreboard.separator_autocolor = stringToBool(v); }}, {"scoreboard.text_autocolor", [](const std::string& v) { param.scoreboard.text_autocolor = stringToBool(v); }}, {"balloon.bouncing_sound", [](const std::string& v) { param.balloon.bouncing_sound = stringToBool(v); }}, {"notification.sound", [](const std::string& v) { param.notification.sound = stringToBool(v); }}, {"service_menu.drop_shadow", [](const std::string& v) { param.service_menu.drop_shadow = stringToBool(v); }}}; static const std::unordered_map> FLOAT_PARAMS = { {"balloon.settings[0].vel", [](const std::string& v) { param.balloon.settings.at(0).vel = std::stof(v); }}, {"balloon.settings[0].grav", [](const std::string& v) { param.balloon.settings.at(0).grav = std::stof(v); }}, {"balloon.settings[1].vel", [](const std::string& v) { param.balloon.settings.at(1).vel = std::stof(v); }}, {"balloon.settings[1].grav", [](const std::string& v) { param.balloon.settings.at(1).grav = std::stof(v); }}, {"balloon.settings[2].vel", [](const std::string& v) { param.balloon.settings.at(2).vel = std::stof(v); }}, {"balloon.settings[2].grav", [](const std::string& v) { param.balloon.settings.at(2).grav = std::stof(v); }}, {"balloon.settings[3].vel", [](const std::string& v) { param.balloon.settings.at(3).vel = std::stof(v); }}, {"balloon.settings[3].grav", [](const std::string& v) { param.balloon.settings.at(3).grav = std::stof(v); }}, {"tabe.min_spawn_time", [](const std::string& v) { param.tabe.min_spawn_time = std::stof(v); }}, {"tabe.max_spawn_time", [](const std::string& v) { param.tabe.max_spawn_time = std::stof(v); }}, {"service_menu.window_message.padding", [](const std::string& v) { param.service_menu.window_message.padding = std::stof(v); }}, {"service_menu.window_message.line_spacing", [](const std::string& v) { param.service_menu.window_message.line_spacing = std::stof(v); }}, {"service_menu.window_message.title_separator_spacing", [](const std::string& v) { param.service_menu.window_message.title_separator_spacing = std::stof(v); }}, {"service_menu.window_message.min_width", [](const std::string& v) { param.service_menu.window_message.min_width = std::stof(v); }}, {"service_menu.window_message.min_height", [](const std::string& v) { param.service_menu.window_message.min_height = std::stof(v); }}, {"service_menu.window_message.max_width_ratio", [](const std::string& v) { param.service_menu.window_message.max_width_ratio = std::stof(v); }}, {"service_menu.window_message.max_height_ratio", [](const std::string& v) { param.service_menu.window_message.max_height_ratio = std::stof(v); }}, {"service_menu.window_message.text_safety_margin", [](const std::string& v) { param.service_menu.window_message.text_safety_margin = std::stof(v); }}, {"service_menu.window_message.animation_duration", [](const std::string& v) { param.service_menu.window_message.animation_duration = std::stof(v); }}}; static const std::unordered_map> INT_PARAMS_EXTRA = {}; static const std::unordered_map> STRING_PARAMS = { {"balloon.color[0]", [](const std::string& v) { param.balloon.color.at(0) = v; }}, {"balloon.color[1]", [](const std::string& v) { param.balloon.color.at(1) = v; }}, {"balloon.color[2]", [](const std::string& v) { param.balloon.color.at(2) = v; }}, {"balloon.color[3]", [](const std::string& v) { param.balloon.color.at(3) = v; }}}; // Lambda para intentar cada mapa de parámetros auto try_map = [&](const auto& param_map) -> bool { auto it = param_map.find(var); if (it != param_map.end()) { it->second(value); return true; } return false; }; // Intentar con todos los mapas if (try_map(INT_PARAMS) || try_map(COLOR_PARAMS) || try_map(BOOL_PARAMS) || try_map(FLOAT_PARAMS) || try_map(STRING_PARAMS)) { return true; } // Casos especiales que necesitan lógica personalizada if (var == "notification.pos_h") { if (value == "LEFT") { param.notification.pos_h = Notifier::Position::LEFT; } else if (value == "MIDDLE") { param.notification.pos_h = Notifier::Position::MIDDLE; } else { param.notification.pos_h = Notifier::Position::RIGHT; } return true; } if (var == "notification.pos_v") { param.notification.pos_v = value == "TOP" ? Notifier::Position::TOP : Notifier::Position::BOTTOM; return true; } return false; // Parámetro no encontrado } } // namespace