#include "options.hpp" #include #include #include #include "../core/defaults.hpp" #include "../external/fkyaml_node.hpp" #include "project.h" namespace Options { // Inicialitzar opcions amb valors per defecte de Defaults:: void init() { #ifdef _DEBUG console = true; #else console = false; #endif // Window window.width = Defaults::Window::WIDTH; window.height = Defaults::Window::HEIGHT; window.fullscreen = false; window.size_increment = Defaults::Window::SIZE_INCREMENT; // Physics physics.rotation_speed = Defaults::Physics::ROTATION_SPEED; physics.acceleration = Defaults::Physics::ACCELERATION; physics.max_velocity = Defaults::Physics::MAX_VELOCITY; physics.friction = Defaults::Physics::FRICTION; physics.enemy_speed = Defaults::Physics::ENEMY_SPEED; physics.bullet_speed = Defaults::Physics::BULLET_SPEED; // Gameplay gameplay.max_enemies = Defaults::Entities::MAX_ORNIS; gameplay.max_bullets = Defaults::Entities::MAX_BALES; // Version version = std::string(Project::VERSION); } // Establir la ruta del fitxer de configuració void setConfigFile(const std::string& path) { config_file_path = path; } // Funcions auxiliars per carregar seccions del YAML static void loadWindowConfigFromYaml(const fkyaml::node& yaml) { if (yaml.contains("window")) { const auto& win = yaml["window"]; if (win.contains("width")) { try { auto val = win["width"].get_value(); window.width = (val >= Defaults::Window::MIN_WIDTH) ? val : Defaults::Window::WIDTH; } catch (...) { window.width = Defaults::Window::WIDTH; } } if (win.contains("height")) { try { auto val = win["height"].get_value(); window.height = (val >= Defaults::Window::MIN_HEIGHT) ? val : Defaults::Window::HEIGHT; } catch (...) { window.height = Defaults::Window::HEIGHT; } } if (win.contains("fullscreen")) { try { window.fullscreen = win["fullscreen"].get_value(); } catch (...) { window.fullscreen = false; } } if (win.contains("size_increment")) { try { auto val = win["size_increment"].get_value(); window.size_increment = (val > 0) ? val : Defaults::Window::SIZE_INCREMENT; } catch (...) { window.size_increment = Defaults::Window::SIZE_INCREMENT; } } } } static void loadPhysicsConfigFromYaml(const fkyaml::node& yaml) { if (yaml.contains("physics")) { const auto& phys = yaml["physics"]; if (phys.contains("rotation_speed")) { try { auto val = phys["rotation_speed"].get_value(); physics.rotation_speed = (val > 0) ? val : Defaults::Physics::ROTATION_SPEED; } catch (...) { physics.rotation_speed = Defaults::Physics::ROTATION_SPEED; } } if (phys.contains("acceleration")) { try { auto val = phys["acceleration"].get_value(); physics.acceleration = (val > 0) ? val : Defaults::Physics::ACCELERATION; } catch (...) { physics.acceleration = Defaults::Physics::ACCELERATION; } } if (phys.contains("max_velocity")) { try { auto val = phys["max_velocity"].get_value(); physics.max_velocity = (val > 0) ? val : Defaults::Physics::MAX_VELOCITY; } catch (...) { physics.max_velocity = Defaults::Physics::MAX_VELOCITY; } } if (phys.contains("friction")) { try { auto val = phys["friction"].get_value(); physics.friction = (val > 0) ? val : Defaults::Physics::FRICTION; } catch (...) { physics.friction = Defaults::Physics::FRICTION; } } if (phys.contains("enemy_speed")) { try { auto val = phys["enemy_speed"].get_value(); physics.enemy_speed = (val > 0) ? val : Defaults::Physics::ENEMY_SPEED; } catch (...) { physics.enemy_speed = Defaults::Physics::ENEMY_SPEED; } } if (phys.contains("bullet_speed")) { try { auto val = phys["bullet_speed"].get_value(); physics.bullet_speed = (val > 0) ? val : Defaults::Physics::BULLET_SPEED; } catch (...) { physics.bullet_speed = Defaults::Physics::BULLET_SPEED; } } } } static void loadGameplayConfigFromYaml(const fkyaml::node& yaml) { if (yaml.contains("gameplay")) { const auto& game = yaml["gameplay"]; if (game.contains("max_enemies")) { try { auto val = game["max_enemies"].get_value(); gameplay.max_enemies = (val > 0 && val <= 50) ? val : Defaults::Entities::MAX_ORNIS; } catch (...) { gameplay.max_enemies = Defaults::Entities::MAX_ORNIS; } } if (game.contains("max_bullets")) { try { auto val = game["max_bullets"].get_value(); gameplay.max_bullets = (val > 0 && val <= 10) ? val : Defaults::Entities::MAX_BALES; } catch (...) { gameplay.max_bullets = Defaults::Entities::MAX_BALES; } } } } // Carregar configuració des del fitxer YAML auto loadFromFile() -> bool { const std::string CONFIG_VERSION = std::string(Project::VERSION); std::ifstream file(config_file_path); if (!file.good()) { // El fitxer no existeix → crear-ne un de nou amb valors per defecte if (console) { std::cout << "Fitxer de config no trobat, creant-ne un de nou: " << config_file_path << '\n'; } saveToFile(); return true; } // Llegir tot el contingut del fitxer std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); file.close(); try { // Parsejar YAML auto yaml = fkyaml::node::deserialize(content); // Validar versió if (yaml.contains("version")) { version = yaml["version"].get_value(); } if (CONFIG_VERSION != version) { // Versió incompatible → regenerar config if (console) { std::cout << "Versió de config incompatible (esperada: " << CONFIG_VERSION << ", trobada: " << version << "), regenerant config\n"; } init(); saveToFile(); return true; } // Carregar seccions loadWindowConfigFromYaml(yaml); loadPhysicsConfigFromYaml(yaml); loadGameplayConfigFromYaml(yaml); if (console) { std::cout << "Config carregada correctament des de: " << config_file_path << '\n'; } return true; } catch (const fkyaml::exception& e) { // Error de parsejat YAML → regenerar config if (console) { std::cerr << "Error parsejant YAML: " << e.what() << '\n'; std::cerr << "Creant config nou amb valors per defecte\n"; } init(); saveToFile(); return true; } } // Guardar configuració al fitxer YAML auto saveToFile() -> bool { std::ofstream file(config_file_path); if (!file.is_open()) { if (console) { std::cerr << "No s'ha pogut obrir el fitxer de config per escriure: " << config_file_path << '\n'; } return false; } // Escriure manualment per controlar format i comentaris file << "# Orni Attack - Fitxer de Configuració\n"; file << "# Auto-generat. Les edicions manuals es preserven si són " "vàlides.\n\n"; file << "version: \"" << Project::VERSION << "\"\n\n"; file << "# FINESTRA\n"; file << "window:\n"; file << " width: " << window.width << "\n"; file << " height: " << window.height << "\n"; file << " fullscreen: " << (window.fullscreen ? "true" : "false") << "\n"; file << " size_increment: " << window.size_increment << "\n\n"; file << "# FÍSICA (tots els valors en px/s, rad/s, etc.)\n"; file << "physics:\n"; file << " rotation_speed: " << physics.rotation_speed << " # rad/s\n"; file << " acceleration: " << physics.acceleration << " # px/s²\n"; file << " max_velocity: " << physics.max_velocity << " # px/s\n"; file << " friction: " << physics.friction << " # px/s²\n"; file << " enemy_speed: " << physics.enemy_speed << " # unitats/frame\n"; file << " bullet_speed: " << physics.bullet_speed << " # unitats/frame\n\n"; file << "# GAMEPLAY\n"; file << "gameplay:\n"; file << " max_enemies: " << gameplay.max_enemies << "\n"; file << " max_bullets: " << gameplay.max_bullets << "\n"; file.close(); if (console) { std::cout << "Config guardada a: " << config_file_path << '\n'; } return true; } } // namespace Options