#pragma once #include // Tweaks de jugabilitat persistents per usuari. Carregat de // `gameplay.yaml` dins la carpeta de sistema (vegeu // `Director::createSystemFolder` per la ubicació real per plataforma). // // Diferent d'UiConfig (data/config/ui.yaml, només lectura): aquest fitxer // és escrivible i el ServiceMenu en modifica els valors. Els defaults // compilats són els que veuen els nous usuaris fins que toquen el menú. // // Política d'integritat: davant qualsevol irregularitat (fitxer absent, // parse error, `version` absent o diferent, clau requerida absent o de // tipus incorrecte), `load()` reseteja a defaults i reescriu el fitxer. // No es preserven fitxers parcialment vàlids — així evitem dragar // versions antigues incoherents quan l'esquema evolucioni. class GameplayConfig { public: // Esquema actual del fitxer. Incrementar quan canviï l'estructura // (renomenar/treure claus o canviar semàntica). Els fitxers d'usuari // amb una `version` distinta es reescriuen amb els defaults nous. // Afegir noves claus opcionals no requereix bump si els defaults // compilats són equivalents al comportament anterior. static constexpr int CURRENT_VERSION = 1; static auto get() -> GameplayConfig&; GameplayConfig(const GameplayConfig&) = delete; GameplayConfig(GameplayConfig&&) = delete; auto operator=(const GameplayConfig&) -> GameplayConfig& = delete; auto operator=(GameplayConfig&&) -> GameplayConfig& = delete; // Llig el fitxer i guarda la ruta per a `save()`. Si no existeix, // l'escriu amb els defaults compilats. Idempotent: pot cridar-se // múltiples vegades (l'última crida fixa el path actiu). void load(const std::string& file_path); // Persisteix l'estat actual al path passat a `load()`. Cridat pel // ServiceMenu a cada canvi de toggle. No-op si `load()` no s'ha // cridat encara (sense path no podem escriure enlloc útil). void save() const; // Tweaks. Defaults: tots true. // // - whip_damage_pierces_walls: el dany del látigo travessa sarcòfags // (NO el mur extern del playfield, que retalla igualment per // evitar que el rect surti de la sala visible). // - friendly_fire: un latigazo pot impactar l'altre jugador. // - players_collide: els jugadors col·lisionen físicament entre si // en lloc de travessar-se. [[nodiscard]] auto whipDamagePiercesWalls() const -> bool { return whip_damage_pierces_walls_; } [[nodiscard]] auto friendlyFire() const -> bool { return friendly_fire_; } [[nodiscard]] auto playersCollide() const -> bool { return players_collide_; } void setWhipDamagePiercesWalls(bool v) { whip_damage_pierces_walls_ = v; } void setFriendlyFire(bool v) { friendly_fire_ = v; } void setPlayersCollide(bool v) { players_collide_ = v; } private: GameplayConfig() = default; ~GameplayConfig() = default; // Ruta absoluta al fitxer persistit. Buida fins que algú crida // `load()` per primera vegada; mentre estigui buida, `save()` és no-op. std::string file_path_; bool whip_damage_pierces_walls_{true}; bool friendly_fire_{true}; bool players_collide_{true}; };