Files
coffee_crisis_arcade_edition/source/options.hpp

316 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <SDL3/SDL.h> // Para SDL_ScaleMode
#include <array> // Para array
#include <cstddef> // Para size_t
#include <exception> // Para exception
#include <fstream> // Para basic_ostream, operator<<, basic_ofstream, basic_ostream::operator<<, ofstream
#include <memory> // Para shared_ptr, __shared_ptr_access, swap
#include <stdexcept> // Para out_of_range, invalid_argument
#include <string> // Para char_traits, basic_string, string, operator==, operator<<, swap, stoi
#include <string_view> // Para string_view
#include <utility> // Para move
#include <vector> // Para vector
#include "defaults.hpp"
#include "difficulty.hpp" // for Code
#include "input.hpp" // for Input
#include "lang.hpp" // for Code
#include "manage_hiscore_table.hpp" // for ManageHiScoreTable, Table
#include "player.hpp" // for Player
// --- Namespace Options: gestión de configuración y opciones del juego ---
namespace Options {
// --- Estructuras ---
struct PostFXPreset {
std::string name;
float vignette{0.6F};
float scanlines{0.7F};
float chroma{0.15F};
float mask{0.0F};
float gamma{0.0F};
float curvature{0.0F};
float bleeding{0.0F};
float flicker{0.0F};
};
struct Window {
std::string caption = Defaults::Window::CAPTION; // Texto que aparece en la barra de título de la ventana
int zoom = Defaults::Window::ZOOM; // Valor por el que se multiplica el tamaño de la ventana
int max_zoom = Defaults::Window::MAX_ZOOM; // Tamaño máximo para que la ventana no sea mayor que la pantalla
};
struct Video {
SDL_ScaleMode scale_mode = Defaults::Video::SCALE_MODE; // Filtro usado para el escalado de la imagen
bool fullscreen = Defaults::Video::FULLSCREEN; // Indica si se usa pantalla completa
bool vsync = Defaults::Video::VSYNC; // Indica si se usa vsync
bool integer_scale = Defaults::Video::INTEGER_SCALE; // Indica si se usa escalado entero
bool postfx = Defaults::Video::POSTFX; // Indica si se usan efectos PostFX
int supersampling = Defaults::Video::SUPERSAMPLING; // Factor de supersampling: 1=off, 2=2×, 3=3×
std::string info; // Información sobre el modo de vídeo
};
struct Music {
bool enabled = Defaults::Music::ENABLED; // Indica si la música suena o no
int volume = Defaults::Music::VOLUME; // Volumen de la música
};
struct Sound {
bool enabled = Defaults::Sound::ENABLED; // Indica si los sonidos suenan o no
int volume = Defaults::Sound::VOLUME; // Volumen de los sonidos
};
struct Audio {
Music music; // Opciones para la música
Sound sound; // Opciones para los efectos de sonido
bool enabled = Defaults::Audio::ENABLED; // Indica si el audio está activo o no
int volume = Defaults::Audio::VOLUME; // Volumen general del audio
};
struct Settings {
int config_version = 2; // Versión del archivo de configuración
Difficulty::Code difficulty = Difficulty::Code::NORMAL; // Dificultad del juego
Lang::Code language = Lang::Code::VALENCIAN; // Idioma usado en el juego
bool autofire = Defaults::Settings::AUTOFIRE; // Indicador de autofire
bool shutdown_enabled = Defaults::Settings::SHUTDOWN_ENABLED; // Especifica si se puede apagar el sistema
Table hi_score_table; // Tabla de mejores puntuaciones
std::vector<int> glowing_entries = {ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}; // Últimas posiciones de entrada en la tabla
std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
std::string controllers_file; // Ruta al fichero con las configuraciones de los mandos
std::string params_file = Defaults::Settings::PARAMS_FILE; // Ruta al fichero de parámetros del juego
// Reinicia las últimas entradas de puntuación
void clearLastHiScoreEntries() {
glowing_entries.at(0) = ManageHiScoreTable::NO_ENTRY;
glowing_entries.at(1) = ManageHiScoreTable::NO_ENTRY;
}
};
struct Gamepad {
std::shared_ptr<Input::Gamepad> instance = nullptr; // Referencia al mando
std::string name; // Nombre del mando
std::string path; // Ruta física del dispositivo
Player::Id player_id; // Jugador asociado al mando
Gamepad(Player::Id custom_player_id = Player::Id::NO_PLAYER)
: player_id(custom_player_id) {}
};
// --- Clases ---
class GamepadManager {
public:
void init() {
gamepads_[0] = Gamepad(Player::Id::PLAYER1);
gamepads_[1] = Gamepad(Player::Id::PLAYER2);
}
// Acceso directo por player_id (más intuitivo)
auto getGamepad(Player::Id player_id) -> Gamepad& {
return gamepads_[playerIdToIndex(player_id)];
}
[[nodiscard]] auto getGamepad(Player::Id player_id) const -> const Gamepad& {
return gamepads_[playerIdToIndex(player_id)];
}
// Acceso por índice (más eficiente si ya tienes el índice)
auto operator[](size_t index) -> Gamepad& {
if (index >= MAX_PLAYERS) {
throw std::out_of_range("Invalid gamepad index");
}
return gamepads_[index];
}
auto operator[](size_t index) const -> const Gamepad& {
if (index >= MAX_PLAYERS) {
throw std::out_of_range("Invalid gamepad index");
}
return gamepads_[index];
}
auto assignGamepadToPlayer(Player::Id player_id,
std::shared_ptr<Input::Gamepad> instance,
const std::string& name) -> bool {
try {
auto& gamepad = getGamepad(player_id);
gamepad.instance = std::move(instance);
gamepad.name = name;
return true;
} catch (const std::exception&) {
return false;
}
}
void swapPlayers() {
std::swap(gamepads_[0].instance, gamepads_[1].instance);
std::swap(gamepads_[0].name, gamepads_[1].name);
std::swap(gamepads_[0].path, gamepads_[1].path);
resyncGamepadsWithPlayers();
}
void resyncGamepadsWithPlayers() {
for (const auto& player : players_) {
switch (player->getId()) {
case Player::Id::PLAYER1:
player->setGamepad(gamepads_[0].instance);
break;
case Player::Id::PLAYER2:
player->setGamepad(gamepads_[1].instance);
break;
default:
break;
}
}
}
void saveToFile(std::ofstream& file) const {
for (size_t i = 0; i < MAX_PLAYERS; ++i) {
const auto& gamepad = gamepads_[i];
file << " - name: \"" << (gamepad.path.empty() ? "" : gamepad.name) << "\"\n";
file << " path: \"" << gamepad.path << "\"\n";
file << " player: " << static_cast<int>(gamepad.player_id) << "\n";
}
}
// Método helper para parseAndSetController
auto setControllerProperty(size_t controller_index,
const std::string& property,
const std::string& value) -> bool {
if (controller_index >= MAX_PLAYERS) {
return false;
}
auto& gamepad = gamepads_[controller_index];
if (property == "name") {
gamepad.name = value;
return true;
}
if (property == "path") {
gamepad.path = value;
return true;
}
if (property == "player") {
try {
int player_int = std::stoi(value);
if (player_int == 1) {
gamepad.player_id = Player::Id::PLAYER1;
} else if (player_int == 2) {
gamepad.player_id = Player::Id::PLAYER2;
} else {
return false;
}
return true;
} catch (const std::exception&) {
return false;
}
}
return false;
}
void addPlayer(const std::shared_ptr<Player>& player) { players_.push_back(player); } // Añade un jugador a la lista
void clearPlayers() { players_.clear(); } // Limpia la lista de jugadores
// Asigna el mando a un jugador
void assignTo(const Input::Gamepad& gamepad, Player::Id player_id) {
}
// Asigna los mandos físicos basándose en la configuración actual de nombres.
void assignAndLinkGamepads();
// Iteradores
auto begin() { return gamepads_.begin(); }
auto end() { return gamepads_.end(); }
[[nodiscard]] auto begin() const { return gamepads_.begin(); }
[[nodiscard]] auto end() const { return gamepads_.end(); }
[[nodiscard]] static auto size() -> size_t { return MAX_PLAYERS; }
private:
static constexpr std::string_view UNASSIGNED_TEXT = "---";
static constexpr size_t MAX_PLAYERS = 2;
std::array<Gamepad, MAX_PLAYERS> gamepads_; // Punteros a las estructuras de mandos de Options
std::vector<std::shared_ptr<Player>> players_; // Punteros a los jugadores
// Convierte Player::Id a índice del array
[[nodiscard]] static auto playerIdToIndex(Player::Id player_id) -> size_t {
switch (player_id) {
case Player::Id::PLAYER1:
return 0;
case Player::Id::PLAYER2:
return 1;
default:
throw std::invalid_argument("Invalid player ID");
}
}
void assignGamepadsByPath(
const std::array<std::string, MAX_PLAYERS>& desired_paths,
const std::vector<std::shared_ptr<Input::Gamepad>>& physical_gamepads, // NOLINT(readability-avoid-const-params-in-decls)
std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances);
void assignRemainingGamepads(
const std::vector<std::shared_ptr<Input::Gamepad>>& physical_gamepads, // NOLINT(readability-avoid-const-params-in-decls)
std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances);
void clearUnassignedGamepadSlots();
[[nodiscard]] static auto isGamepadAssigned(
const std::shared_ptr<Input::Gamepad>& physical_gamepad,
const std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances) -> bool; // NOLINT(readability-avoid-const-params-in-decls)
};
struct Keyboard {
Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado
std::vector<std::shared_ptr<Player>> players; // Punteros a los jugadores
void addPlayer(const std::shared_ptr<Player>& player) { players.push_back(player); } // Añade un jugador a la lista
void clearPlayers() { players.clear(); } // Limpia la lista de jugadores
// Asigna el teclado a un jugador
void assignTo(Player::Id player_id) {
this->player_id = player_id;
for (auto& player : players) {
player->setUsesKeyboard(player->getId() == player_id);
}
}
};
struct PendingChanges {
Lang::Code new_language = Lang::Code::VALENCIAN; // Idioma en espera de aplicar
Difficulty::Code new_difficulty = Difficulty::Code::NORMAL; // Dificultad en espera de aplicar
bool has_pending_changes = false; // Indica si hay cambios pendientes
};
// --- Variables ---
extern Window window; // Opciones de la ventana
extern Settings settings; // Opciones del juego
extern Video video; // Opciones de vídeo
extern Audio audio; // Opciones de audio
extern GamepadManager gamepad_manager; // Manager de mandos para cada jugador
extern Keyboard keyboard; // Opciones para el teclado
extern PendingChanges pending_changes; // Opciones que se aplican al cerrar
extern std::vector<PostFXPreset> postfx_presets; // Lista de presets de PostFX
extern int current_postfx_preset; // Índice del preset PostFX activo
extern std::string postfx_file_path; // Ruta al fichero de presets PostFX
// --- Funciones ---
void init(); // Inicializa las opciones del programa
void setConfigFile(const std::string& file_path); // Establece el fichero de configuración
void setControllersFile(const std::string& file_path); // Establece el fichero de configuración de mandos
void setPostFXFile(const std::string& path); // Establece el fichero de presets PostFX
auto loadPostFXFromFile() -> bool; // Carga los presets PostFX desde fichero
auto savePostFXToFile() -> bool; // Guarda los presets PostFX por defecto al fichero
auto loadFromFile() -> bool; // Carga el fichero de configuración
auto saveToFile() -> bool; // Guarda el fichero de configuración
void setKeyboardToPlayer(Player::Id player_id); // Asigna el teclado al jugador
void swapKeyboard(); // Intercambia el teclado de jugador
void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
auto getPlayerWhoUsesKeyboard() -> Player::Id; // Averigua quién está usando el teclado
auto playerIdToString(Player::Id player_id) -> std::string; // Convierte un player id a texto segun Lang
auto stringToPlayerId(const std::string& name) -> Player::Id; // Convierte un texto a player id segun Lang
void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables
void checkPendingChanges(); // Verifica si hay cambios pendientes
auto assignGamepadByName(const std::string& gamepad_name, Player::Id player_id) -> bool; // Buscar y asignar un mando disponible por nombre
} // namespace Options