modernitzat el sistema d'opcions
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
#include "core/rendering/text.h" // for Text, TXT_CENTER, TXT_COLOR, TXT_STROKE
|
||||
#include "core/resources/asset.h" // for Asset
|
||||
#include "core/resources/resource.h"
|
||||
#include "game/defaults.hpp" // for GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT
|
||||
#include "game/options.hpp" // for Options::video, Options::settings
|
||||
|
||||
#ifndef NO_SHADERS
|
||||
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // for Rendering::SDL3GPUShader
|
||||
@@ -59,17 +61,14 @@ namespace {
|
||||
#endif // __EMSCRIPTEN__
|
||||
|
||||
// Constructor
|
||||
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options) {
|
||||
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset) {
|
||||
// Inicializa variables
|
||||
this->window = window;
|
||||
this->renderer = renderer;
|
||||
this->options = options;
|
||||
this->asset = asset;
|
||||
|
||||
gameCanvasWidth = options->gameWidth;
|
||||
gameCanvasHeight = options->gameHeight;
|
||||
borderWidth = options->borderWidth * 2;
|
||||
borderHeight = options->borderHeight * 2;
|
||||
gameCanvasWidth = GAMECANVAS_WIDTH;
|
||||
gameCanvasHeight = GAMECANVAS_HEIGHT;
|
||||
|
||||
// Define el color del borde para el modo de pantalla completa
|
||||
borderColor = {0x00, 0x00, 0x00};
|
||||
@@ -80,7 +79,7 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options
|
||||
// Mirror del pattern de jaildoctors_dilemma (que usa exactament 256×192 i
|
||||
// funciona) on `initSDLVideo` configura la presentation abans de crear cap
|
||||
// textura.
|
||||
setVideoMode(options->videoMode != 0);
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
|
||||
// Força al window manager a completar el resize/posicionat abans de passar
|
||||
// la ventana al dispositiu GPU. Sense açò en Linux/X11 hi ha un race
|
||||
@@ -92,10 +91,10 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options
|
||||
// ARGB8888 per simplificar el readback cap al pipeline SDL3 GPU.
|
||||
gameCanvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, gameCanvasWidth, gameCanvasHeight);
|
||||
if (gameCanvas != nullptr) {
|
||||
SDL_SetTextureScaleMode(gameCanvas, options->filter == FILTER_NEAREST ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR);
|
||||
SDL_SetTextureScaleMode(gameCanvas, Options::video.scale_mode);
|
||||
}
|
||||
if (gameCanvas == nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "gameCanvas could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +181,7 @@ void Screen::blit() {
|
||||
}
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
|
||||
if (options->videoShaderEnabled) {
|
||||
if (Options::video.shader.enabled) {
|
||||
// Ruta normal: shader amb els seus params.
|
||||
shader_backend_->uploadPixels(pixel_buffer_.data(), gameCanvasWidth, gameCanvasHeight);
|
||||
shader_backend_->render();
|
||||
@@ -237,54 +236,54 @@ void Screen::setVideoMode(bool fullscreen) {
|
||||
|
||||
// Cambia entre pantalla completa y ventana
|
||||
void Screen::toggleVideoMode() {
|
||||
setVideoMode(options->videoMode == 0);
|
||||
setVideoMode(!Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Reduce el zoom de la ventana
|
||||
auto Screen::decWindowZoom() -> bool {
|
||||
if (options->videoMode != 0) { return false; }
|
||||
const int PREV = options->windowSize;
|
||||
options->windowSize = std::max(options->windowSize - 1, WINDOW_ZOOM_MIN);
|
||||
if (options->windowSize == PREV) { return false; }
|
||||
if (Options::video.fullscreen) { return false; }
|
||||
const int PREV = Options::window.zoom;
|
||||
Options::window.zoom = std::max(Options::window.zoom - 1, WINDOW_ZOOM_MIN);
|
||||
if (Options::window.zoom == PREV) { return false; }
|
||||
setVideoMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Aumenta el zoom de la ventana
|
||||
auto Screen::incWindowZoom() -> bool {
|
||||
if (options->videoMode != 0) { return false; }
|
||||
const int PREV = options->windowSize;
|
||||
options->windowSize = std::min(options->windowSize + 1, WINDOW_ZOOM_MAX);
|
||||
if (options->windowSize == PREV) { return false; }
|
||||
if (Options::video.fullscreen) { return false; }
|
||||
const int PREV = Options::window.zoom;
|
||||
Options::window.zoom = std::min(Options::window.zoom + 1, WINDOW_ZOOM_MAX);
|
||||
if (Options::window.zoom == PREV) { return false; }
|
||||
setVideoMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Establece el zoom de la ventana directamente
|
||||
auto Screen::setWindowZoom(int zoom) -> bool {
|
||||
if (options->videoMode != 0) { return false; }
|
||||
if (Options::video.fullscreen) { return false; }
|
||||
if (zoom < WINDOW_ZOOM_MIN || zoom > WINDOW_ZOOM_MAX) { return false; }
|
||||
if (zoom == options->windowSize) { return false; }
|
||||
options->windowSize = zoom;
|
||||
if (zoom == Options::window.zoom) { return false; }
|
||||
Options::window.zoom = zoom;
|
||||
setVideoMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Establece el escalado entero
|
||||
void Screen::setIntegerScale(bool enabled) {
|
||||
if (options->integerScale == enabled) { return; }
|
||||
options->integerScale = enabled;
|
||||
setVideoMode(options->videoMode != 0);
|
||||
if (Options::video.integer_scale == enabled) { return; }
|
||||
Options::video.integer_scale = enabled;
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Alterna el escalado entero
|
||||
void Screen::toggleIntegerScale() {
|
||||
setIntegerScale(!options->integerScale);
|
||||
setIntegerScale(!Options::video.integer_scale);
|
||||
}
|
||||
|
||||
// Establece el V-Sync
|
||||
void Screen::setVSync(bool enabled) {
|
||||
options->vSync = enabled;
|
||||
Options::video.vsync = enabled;
|
||||
SDL_SetRenderVSync(renderer, enabled ? 1 : SDL_RENDERER_VSYNC_DISABLED);
|
||||
#ifndef NO_SHADERS
|
||||
if (shader_backend_) {
|
||||
@@ -295,7 +294,7 @@ void Screen::setVSync(bool enabled) {
|
||||
|
||||
// Alterna el V-Sync
|
||||
void Screen::toggleVSync() {
|
||||
setVSync(!options->vSync);
|
||||
setVSync(!Options::video.vsync);
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
@@ -322,15 +321,9 @@ void Screen::applyFullscreen(bool fullscreen) {
|
||||
|
||||
// Calcula windowWidth/Height/dest para el modo ventana y aplica SDL_SetWindowSize
|
||||
void Screen::applyWindowedLayout() {
|
||||
if (options->borderEnabled) {
|
||||
windowWidth = gameCanvasWidth + borderWidth;
|
||||
windowHeight = gameCanvasHeight + borderHeight;
|
||||
dest = {0 + (borderWidth / 2), 0 + (borderHeight / 2), gameCanvasWidth, gameCanvasHeight};
|
||||
} else {
|
||||
windowWidth = gameCanvasWidth;
|
||||
windowHeight = gameCanvasHeight;
|
||||
dest = {0, 0, gameCanvasWidth, gameCanvasHeight};
|
||||
}
|
||||
windowWidth = gameCanvasWidth;
|
||||
windowHeight = gameCanvasHeight;
|
||||
dest = {0, 0, gameCanvasWidth, gameCanvasHeight};
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
windowWidth *= WASM_RENDER_SCALE;
|
||||
@@ -340,7 +333,7 @@ void Screen::applyWindowedLayout() {
|
||||
#endif
|
||||
|
||||
// Modifica el tamaño de la ventana
|
||||
SDL_SetWindowSize(window, windowWidth * options->windowSize, windowHeight * options->windowSize);
|
||||
SDL_SetWindowSize(window, windowWidth * Options::window.zoom, windowHeight * Options::window.zoom);
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||
}
|
||||
|
||||
@@ -350,9 +343,9 @@ void Screen::applyFullscreenLayout() {
|
||||
computeFullscreenGameRect();
|
||||
}
|
||||
|
||||
// Calcula el rectángulo dest para fullscreen: integerScale / keepAspect / stretched
|
||||
// Calcula el rectángulo dest para fullscreen: integer_scale / aspect ratio
|
||||
void Screen::computeFullscreenGameRect() {
|
||||
if (options->integerScale) {
|
||||
if (Options::video.integer_scale) {
|
||||
// Calcula el tamaño de la escala máxima
|
||||
int scale = 0;
|
||||
while (((gameCanvasWidth * (scale + 1)) <= windowWidth) && ((gameCanvasHeight * (scale + 1)) <= windowHeight)) {
|
||||
@@ -363,7 +356,8 @@ void Screen::computeFullscreenGameRect() {
|
||||
dest.h = gameCanvasHeight * scale;
|
||||
dest.x = (windowWidth - dest.w) / 2;
|
||||
dest.y = (windowHeight - dest.h) / 2;
|
||||
} else if (options->keepAspect) {
|
||||
} else {
|
||||
// Manté la relació d'aspecte sense escalat enter (letterbox/pillarbox).
|
||||
float ratio = (float)gameCanvasWidth / (float)gameCanvasHeight;
|
||||
if ((windowWidth - gameCanvasWidth) >= (windowHeight - gameCanvasHeight)) {
|
||||
dest.h = windowHeight;
|
||||
@@ -376,21 +370,13 @@ void Screen::computeFullscreenGameRect() {
|
||||
dest.x = (windowWidth - dest.w) / 2;
|
||||
dest.y = (windowHeight - dest.h) / 2;
|
||||
}
|
||||
} else {
|
||||
dest.w = windowWidth;
|
||||
dest.h = windowHeight;
|
||||
dest.x = dest.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Aplica la logical presentation y persiste el estado en options
|
||||
void Screen::applyLogicalPresentation(bool fullscreen) {
|
||||
SDL_SetRenderLogicalPresentation(renderer, windowWidth, windowHeight, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
|
||||
// Actualiza las opciones
|
||||
options->videoMode = fullscreen ? SDL_WINDOW_FULLSCREEN : 0;
|
||||
options->screen.windowWidth = windowWidth;
|
||||
options->screen.windowHeight = windowHeight;
|
||||
Options::video.fullscreen = fullscreen;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -436,13 +422,13 @@ void Screen::handleCanvasResized() {
|
||||
// La crida a SDL_SetWindowFullscreen + SDL_SetRenderLogicalPresentation
|
||||
// que fa setVideoMode és l'única manera de resincronitzar l'estat intern
|
||||
// de SDL amb el canvas HTML real.
|
||||
setVideoMode(options->videoMode != 0);
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Screen::syncFullscreenFlagFromBrowser(bool isFullscreen) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
options->videoMode = isFullscreen ? SDL_WINDOW_FULLSCREEN : 0;
|
||||
Options::video.fullscreen = isFullscreen;
|
||||
#else
|
||||
(void)isFullscreen;
|
||||
#endif
|
||||
@@ -474,10 +460,7 @@ void Screen::applyShaderParams() {
|
||||
if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) {
|
||||
return;
|
||||
}
|
||||
const Rendering::ShaderType ACTIVE = options->videoShaderType == 1
|
||||
? Rendering::ShaderType::CRTPI
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
shader_backend_->setActiveShader(ACTIVE);
|
||||
shader_backend_->setActiveShader(Options::video.shader.current_shader);
|
||||
|
||||
// Preset per defecte (carregador YAML pendent). Valors estil "CRT" de CCAE.
|
||||
Rendering::PostFXParams POSTFX;
|
||||
@@ -497,17 +480,17 @@ void Screen::initShaders() {
|
||||
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
|
||||
const std::string FALLBACK_DRIVER = "none";
|
||||
shader_backend_->setPreferredDriver(
|
||||
options->videoGpuAcceleration ? options->videoGpuPreferredDriver : FALLBACK_DRIVER);
|
||||
Options::video.gpu.acceleration ? Options::video.gpu.preferred_driver : FALLBACK_DRIVER);
|
||||
}
|
||||
if (!shader_backend_->isHardwareAccelerated()) {
|
||||
const bool ok = shader_backend_->init(window, gameCanvas, "", "");
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Screen::initShaders: SDL3GPUShader::init() = " << (ok ? "OK" : "FAILED") << '\n';
|
||||
}
|
||||
}
|
||||
if (shader_backend_->isHardwareAccelerated()) {
|
||||
shader_backend_->setScaleMode(options->integerScale);
|
||||
shader_backend_->setVSync(options->vSync);
|
||||
shader_backend_->setScaleMode(Options::video.integer_scale);
|
||||
shader_backend_->setVSync(Options::video.vsync);
|
||||
applyShaderParams(); // aplica preset del shader actiu
|
||||
}
|
||||
#endif
|
||||
@@ -526,8 +509,8 @@ void Screen::shutdownShaders() {
|
||||
}
|
||||
|
||||
void Screen::setGpuAcceleration(bool enabled) {
|
||||
if (options->videoGpuAcceleration == enabled) { return; }
|
||||
options->videoGpuAcceleration = enabled;
|
||||
if (Options::video.gpu.acceleration == enabled) { return; }
|
||||
Options::video.gpu.acceleration = enabled;
|
||||
// Soft toggle: el backend es manté viu (vegeu shutdownShaders). El canvi
|
||||
// s'aplica al proper arrencada. S'emet una notificació perquè l'usuari
|
||||
// sap que ha tocat la tecla però el canvi no és immediat.
|
||||
@@ -538,7 +521,7 @@ void Screen::setGpuAcceleration(bool enabled) {
|
||||
}
|
||||
|
||||
void Screen::toggleGpuAcceleration() {
|
||||
setGpuAcceleration(!options->videoGpuAcceleration);
|
||||
setGpuAcceleration(!Options::video.gpu.acceleration);
|
||||
}
|
||||
|
||||
auto Screen::isGpuAccelerated() const -> bool {
|
||||
@@ -550,8 +533,8 @@ auto Screen::isGpuAccelerated() const -> bool {
|
||||
}
|
||||
|
||||
void Screen::setShaderEnabled(bool enabled) {
|
||||
if (options->videoShaderEnabled == enabled) { return; }
|
||||
options->videoShaderEnabled = enabled;
|
||||
if (Options::video.shader.enabled == enabled) { return; }
|
||||
Options::video.shader.enabled = enabled;
|
||||
#ifndef NO_SHADERS
|
||||
if (enabled) {
|
||||
applyShaderParams(); // restaura preset del shader actiu
|
||||
@@ -566,17 +549,17 @@ void Screen::setShaderEnabled(bool enabled) {
|
||||
}
|
||||
|
||||
void Screen::toggleShaderEnabled() {
|
||||
setShaderEnabled(!options->videoShaderEnabled);
|
||||
setShaderEnabled(!Options::video.shader.enabled);
|
||||
}
|
||||
|
||||
auto Screen::isShaderEnabled() const -> bool {
|
||||
return options->videoShaderEnabled;
|
||||
return Options::video.shader.enabled;
|
||||
}
|
||||
|
||||
#ifndef NO_SHADERS
|
||||
void Screen::setActiveShader(Rendering::ShaderType type) {
|
||||
options->videoShaderType = type == Rendering::ShaderType::CRTPI ? 1 : 0;
|
||||
if (options->videoShaderEnabled) {
|
||||
Options::video.shader.current_shader = type;
|
||||
if (Options::video.shader.enabled) {
|
||||
applyShaderParams();
|
||||
}
|
||||
const color_t MAGENTA = {0xFF, 0x00, 0xFF};
|
||||
@@ -586,7 +569,7 @@ void Screen::setActiveShader(Rendering::ShaderType type) {
|
||||
}
|
||||
|
||||
auto Screen::getActiveShader() const -> Rendering::ShaderType {
|
||||
return options->videoShaderType == 1 ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||
return Options::video.shader.current_shader;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -597,6 +580,8 @@ void Screen::toggleActiveShader() {
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
setActiveShader(NEXT);
|
||||
#else
|
||||
options->videoShaderType = options->videoShaderType == 1 ? 0 : 1;
|
||||
Options::video.shader.current_shader = Options::video.shader.current_shader == Rendering::ShaderType::POSTFX
|
||||
? Rendering::ShaderType::CRTPI
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@ namespace Rendering {
|
||||
class Asset;
|
||||
class Text;
|
||||
|
||||
// Tipos de filtro
|
||||
constexpr int FILTER_NEAREST = 0;
|
||||
constexpr int FILTER_LINEAL = 1;
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
// Constantes
|
||||
@@ -35,7 +31,7 @@ class Screen {
|
||||
#endif
|
||||
|
||||
// Constructor y destructor
|
||||
Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options);
|
||||
Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset);
|
||||
~Screen();
|
||||
|
||||
// Render loop
|
||||
@@ -104,15 +100,12 @@ class Screen {
|
||||
SDL_Renderer *renderer; // El renderizador de la ventana
|
||||
Asset *asset; // Objeto con el listado de recursos
|
||||
SDL_Texture *gameCanvas; // Textura para completar la ventana de juego hasta la pantalla completa
|
||||
options_t *options; // Variable con todas las opciones del programa
|
||||
|
||||
// Variables
|
||||
int windowWidth; // Ancho de la pantalla o ventana
|
||||
int windowHeight; // Alto de la pantalla o ventana
|
||||
int gameCanvasWidth; // Resolución interna del juego. Es el ancho de la textura donde se dibuja el juego
|
||||
int gameCanvasHeight; // Resolución interna del juego. Es el alto de la textura donde se dibuja el juego
|
||||
int borderWidth; // Anchura del borde
|
||||
int borderHeight; // Altura del borde
|
||||
SDL_Rect dest; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
|
||||
color_t borderColor; // Color del borde añadido a la textura de juego para rellenar la pantalla
|
||||
|
||||
|
||||
@@ -21,17 +21,18 @@
|
||||
#include "core/input/input.h" // for Input, inputs_e, INPUT_USE_GAME...
|
||||
#include "core/input/mouse.hpp" // for Mouse::handleEvent, Mouse::upda...
|
||||
#include "core/locale/lang.h" // for Lang, MAX_LANGUAGES, ba_BA, en_UK
|
||||
#include "core/rendering/screen.h" // for FILTER_NEAREST, Screen, FILTER_...
|
||||
#include "core/rendering/screen.h" // for Screen
|
||||
#include "core/rendering/texture.h" // for Texture
|
||||
#include "core/resources/asset.h" // for Asset, assetType
|
||||
#include "core/resources/resource.h"
|
||||
#include "core/resources/resource_helper.h"
|
||||
#include "game/defaults.hpp" // for SECTION_PROG_LOGO, GAMECANVAS_H...
|
||||
#include "game/game.h" // for Game
|
||||
#include "game/options.hpp" // for Options::init, loadFromFile...
|
||||
#include "game/scenes/intro.h" // for Intro
|
||||
#include "game/scenes/logo.h" // for Logo
|
||||
#include "game/scenes/title.h" // for Title
|
||||
#include "utils/utils.h" // for options_t, input_t, boolToString
|
||||
#include "utils/utils.h" // for input_t, boolToString
|
||||
|
||||
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
|
||||
#include <pwd.h>
|
||||
@@ -44,10 +45,10 @@ Director::Director(int argc, const char *argv[]) {
|
||||
section = new section_t();
|
||||
section->name = SECTION_PROG_LOGO;
|
||||
|
||||
// Inicializa las opciones del programa
|
||||
initOptions();
|
||||
// Inicializa las opciones del programa (defaults + dispositivos d'entrada)
|
||||
Options::init();
|
||||
|
||||
// Comprueba los parametros del programa
|
||||
// Comprueba los parametros del programa (pot activar console)
|
||||
checkProgramArguments(argc, argv);
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
@@ -58,6 +59,11 @@ Director::Director(int argc, const char *argv[]) {
|
||||
createSystemFolder("jailgames/coffee_crisis_debug");
|
||||
#endif
|
||||
|
||||
// Estableix el fitxer de configuració i carrega les opcions (o crea el
|
||||
// YAML amb defaults si no existeix).
|
||||
Options::setConfigFile(systemFolder + "/config.yaml");
|
||||
Options::loadFromFile();
|
||||
|
||||
// Inicializa el sistema de recursos (pack + fallback).
|
||||
// En wasm siempre se usa filesystem (MEMFS) porque el propio --preload-file
|
||||
// de emscripten ya empaqueta data/ — no hay resources.pack.
|
||||
@@ -77,16 +83,13 @@ Director::Director(int argc, const char *argv[]) {
|
||||
|
||||
// Crea el objeto que controla los ficheros de recursos
|
||||
asset = new Asset(executablePath);
|
||||
asset->setVerbose(options->console);
|
||||
asset->setVerbose(Options::settings.console);
|
||||
|
||||
// Si falta algún fichero no inicia el programa
|
||||
if (!setFileList()) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Carga el fichero de configuración
|
||||
loadConfigFile();
|
||||
|
||||
// Inicializa SDL
|
||||
initSDL();
|
||||
|
||||
@@ -94,11 +97,11 @@ Director::Director(int argc, const char *argv[]) {
|
||||
initJailAudio();
|
||||
|
||||
// Establece el modo de escalado de texturas
|
||||
Texture::setGlobalScaleMode(options->filter == FILTER_NEAREST ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR);
|
||||
Texture::setGlobalScaleMode(Options::video.scale_mode);
|
||||
|
||||
// Crea los objetos
|
||||
lang = new Lang(asset);
|
||||
lang->setLang(options->language);
|
||||
lang->setLang(Options::settings.language);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
input = new Input("/gamecontrollerdb.txt");
|
||||
@@ -122,10 +125,10 @@ Director::Director(int argc, const char *argv[]) {
|
||||
//
|
||||
// Por eso el constructor de Screen NO carga notificationText desde
|
||||
// Resource; se enlaza después vía `screen->initNotifications()`.
|
||||
screen = new Screen(window, renderer, asset, options);
|
||||
screen = new Screen(window, renderer, asset);
|
||||
|
||||
#ifndef NO_SHADERS
|
||||
if (options->videoGpuAcceleration) {
|
||||
if (Options::video.gpu.acceleration) {
|
||||
screen->initShaders();
|
||||
}
|
||||
#endif
|
||||
@@ -142,7 +145,7 @@ Director::Director(int argc, const char *argv[]) {
|
||||
}
|
||||
|
||||
Director::~Director() {
|
||||
saveConfigFile();
|
||||
Options::saveToFile();
|
||||
|
||||
// Libera las secciones primero: sus destructores tocan audio/render SDL
|
||||
// (p.ej. Intro::~Intro llama a JA_DeleteMusic) y deben ejecutarse antes
|
||||
@@ -162,7 +165,6 @@ Director::~Director() {
|
||||
delete asset;
|
||||
delete input;
|
||||
delete lang;
|
||||
delete options;
|
||||
delete section;
|
||||
|
||||
SDL_DestroyRenderer(renderer);
|
||||
@@ -178,7 +180,7 @@ Director::~Director() {
|
||||
// Inicializa el objeto input
|
||||
void Director::initInput() {
|
||||
// Establece si ha de mostrar mensajes
|
||||
input->setVerbose(options->console);
|
||||
input->setVerbose(Options::settings.console);
|
||||
|
||||
// Busca si hay un mando conectado
|
||||
input->discoverGameController();
|
||||
@@ -237,7 +239,7 @@ bool Director::initSDL() {
|
||||
|
||||
// Inicializa SDL
|
||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "SDL could not initialize!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
@@ -246,15 +248,13 @@ bool Director::initSDL() {
|
||||
std::srand(static_cast<unsigned int>(SDL_GetTicks()));
|
||||
|
||||
// Crea la ventana
|
||||
int incW = 0;
|
||||
int incH = 0;
|
||||
if (options->borderEnabled) {
|
||||
incW = options->borderWidth * 2;
|
||||
incH = options->borderHeight * 2;
|
||||
}
|
||||
window = SDL_CreateWindow(WINDOW_CAPTION, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, 0);
|
||||
window = SDL_CreateWindow(
|
||||
Options::window.caption.c_str(),
|
||||
GAMECANVAS_WIDTH * Options::window.zoom,
|
||||
GAMECANVAS_HEIGHT * Options::window.zoom,
|
||||
0);
|
||||
if (window == nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Window could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
@@ -265,7 +265,7 @@ bool Director::initSDL() {
|
||||
renderer = SDL_CreateRenderer(window, NULL);
|
||||
|
||||
if (renderer == nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Renderer could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
@@ -275,7 +275,7 @@ bool Director::initSDL() {
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
// Activa vsync si es necesario
|
||||
if (options->vSync) {
|
||||
if (Options::video.vsync) {
|
||||
SDL_SetRenderVSync(renderer, 1);
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ bool Director::initSDL() {
|
||||
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
|
||||
|
||||
// Establece el tamaño del buffer de renderizado
|
||||
SDL_SetRenderLogicalPresentation(renderer, options->gameWidth, options->gameHeight, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
SDL_SetRenderLogicalPresentation(renderer, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
|
||||
// Establece el modo de mezcla
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
@@ -291,7 +291,7 @@ bool Director::initSDL() {
|
||||
}
|
||||
}
|
||||
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return success;
|
||||
@@ -306,7 +306,6 @@ bool Director::setFileList() {
|
||||
#endif
|
||||
|
||||
// Ficheros de configuración
|
||||
asset->add(systemFolder + "/config.txt", t_data, false, true);
|
||||
asset->add(systemFolder + "/score.bin", t_data, false, true);
|
||||
asset->add(prefix + "/data/demo/demo.bin", t_data);
|
||||
|
||||
@@ -426,52 +425,6 @@ bool Director::setFileList() {
|
||||
return asset->check();
|
||||
}
|
||||
|
||||
// Inicializa las opciones del programa
|
||||
void Director::initOptions() {
|
||||
// Crea el puntero a la estructura de opciones
|
||||
options = new options_t;
|
||||
|
||||
// Pone unos valores por defecto para las opciones de control
|
||||
options->input.clear();
|
||||
|
||||
input_t inp;
|
||||
inp.id = 0;
|
||||
inp.name = "KEYBOARD";
|
||||
inp.deviceType = INPUT_USE_KEYBOARD;
|
||||
options->input.push_back(inp);
|
||||
|
||||
inp.id = 0;
|
||||
inp.name = "GAME CONTROLLER";
|
||||
inp.deviceType = INPUT_USE_GAMECONTROLLER;
|
||||
options->input.push_back(inp);
|
||||
|
||||
// Opciones de video
|
||||
options->gameWidth = GAMECANVAS_WIDTH;
|
||||
options->gameHeight = GAMECANVAS_HEIGHT;
|
||||
options->videoMode = 0;
|
||||
options->windowSize = 3;
|
||||
options->filter = FILTER_NEAREST;
|
||||
options->vSync = true;
|
||||
options->integerScale = true;
|
||||
options->keepAspect = true;
|
||||
options->borderWidth = 0;
|
||||
options->borderHeight = 0;
|
||||
options->borderEnabled = false;
|
||||
|
||||
// Opciones varios
|
||||
options->playerSelected = 0;
|
||||
options->difficulty = DIFFICULTY_NORMAL;
|
||||
options->language = ba_BA;
|
||||
options->console = false;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// En Emscripten la ventana la gestiona el navegador
|
||||
options->windowSize = 4;
|
||||
options->videoMode = 0;
|
||||
options->integerScale = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Comprueba los parametros del programa
|
||||
void Director::checkProgramArguments(int argc, const char *argv[]) {
|
||||
// Establece la ruta del programa
|
||||
@@ -480,7 +433,7 @@ void Director::checkProgramArguments(int argc, const char *argv[]) {
|
||||
// Comprueba el resto de parametros
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--console") == 0) {
|
||||
options->console = true;
|
||||
Options::settings.console = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,127 +501,6 @@ void Director::createSystemFolder(const std::string &folder) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Carga el fichero de configuración
|
||||
bool Director::loadConfigFile() {
|
||||
// Indicador de éxito en la carga
|
||||
bool success = true;
|
||||
|
||||
// Variables para manejar el fichero
|
||||
const std::string filePath = "config.txt";
|
||||
std::string line;
|
||||
std::ifstream file(asset->get(filePath));
|
||||
|
||||
// Si el fichero se puede abrir
|
||||
if (file.good()) {
|
||||
// Procesa el fichero linea a linea
|
||||
if (options->console) {
|
||||
std::cout << "Reading file " << filePath << std::endl;
|
||||
}
|
||||
while (std::getline(file, line)) {
|
||||
// Comprueba que la linea no sea un comentario
|
||||
if (line.substr(0, 1) != "#") {
|
||||
// Encuentra la posición del caracter '='
|
||||
int pos = line.find("=");
|
||||
// Procesa las dos subcadenas
|
||||
if (!setOptions(options, line.substr(0, pos), line.substr(pos + 1, line.length()))) {
|
||||
if (options->console) {
|
||||
std::cout << "Warning: file " << filePath << std::endl;
|
||||
std::cout << "Unknown parameter " << line.substr(0, pos).c_str() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
if (options->console) {
|
||||
std::cout << "Closing file " << filePath << std::endl;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
// El fichero no existe
|
||||
else { // Crea el fichero con los valores por defecto
|
||||
saveConfigFile();
|
||||
}
|
||||
|
||||
// Normaliza los valores
|
||||
if (options->videoMode != 0 && options->videoMode != SDL_WINDOW_FULLSCREEN) {
|
||||
options->videoMode = 0;
|
||||
}
|
||||
|
||||
if (options->windowSize < 1 || options->windowSize > 4) {
|
||||
options->windowSize = 3;
|
||||
}
|
||||
|
||||
if (options->language < 0 || options->language > MAX_LANGUAGES) {
|
||||
options->language = en_UK;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Guarda el fichero de configuración
|
||||
bool Director::saveConfigFile() {
|
||||
bool success = true;
|
||||
|
||||
// Crea y abre el fichero de texto
|
||||
std::ofstream file(asset->get("config.txt"));
|
||||
|
||||
if (file.good()) {
|
||||
if (options->console) {
|
||||
std::cout << asset->get("config.txt") << " open for writing" << std::endl;
|
||||
}
|
||||
} else {
|
||||
if (options->console) {
|
||||
std::cout << asset->get("config.txt") << " can't be opened" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Opciones g´raficas
|
||||
file << "## VISUAL OPTIONS\n";
|
||||
if (options->videoMode == 0) {
|
||||
file << "videoMode=0\n";
|
||||
}
|
||||
|
||||
else if (options->videoMode == SDL_WINDOW_FULLSCREEN) {
|
||||
file << "videoMode=SDL_WINDOW_FULLSCREEN\n";
|
||||
}
|
||||
|
||||
file << "windowSize=" + std::to_string(options->windowSize) + "\n";
|
||||
|
||||
if (options->filter == FILTER_NEAREST) {
|
||||
file << "filter=FILTER_NEAREST\n";
|
||||
} else {
|
||||
file << "filter=FILTER_LINEAL\n";
|
||||
}
|
||||
|
||||
file << "vSync=" + boolToString(options->vSync) + "\n";
|
||||
file << "integerScale=" + boolToString(options->integerScale) + "\n";
|
||||
file << "keepAspect=" + boolToString(options->keepAspect) + "\n";
|
||||
file << "borderEnabled=" + boolToString(options->borderEnabled) + "\n";
|
||||
file << "borderWidth=" + std::to_string(options->borderWidth) + "\n";
|
||||
file << "borderHeight=" + std::to_string(options->borderHeight) + "\n";
|
||||
|
||||
// Opciones de GPU / shaders (post-procesado)
|
||||
file << "videoGpuAcceleration=" + boolToString(options->videoGpuAcceleration) + "\n";
|
||||
file << "videoGpuPreferredDriver=" + options->videoGpuPreferredDriver + "\n";
|
||||
file << "videoShaderEnabled=" + boolToString(options->videoShaderEnabled) + "\n";
|
||||
file << "videoShaderType=" + std::to_string(options->videoShaderType) + "\n";
|
||||
|
||||
// Otras opciones del programa
|
||||
file << "\n## OTHER OPTIONS\n";
|
||||
file << "language=" + std::to_string(options->language) + "\n";
|
||||
file << "difficulty=" + std::to_string(options->difficulty) + "\n";
|
||||
file << "input0=" + std::to_string(options->input[0].deviceType) + "\n";
|
||||
file << "input1=" + std::to_string(options->input[1].deviceType) + "\n";
|
||||
|
||||
// Cierra el fichero
|
||||
file.close();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Gestiona las transiciones entre secciones
|
||||
void Director::handleSectionTransition() {
|
||||
// Determina qué sección debería estar activa
|
||||
@@ -707,11 +539,11 @@ void Director::handleSectionTransition() {
|
||||
intro = std::make_unique<Intro>(renderer, screen, asset, input, lang, section);
|
||||
break;
|
||||
case ActiveSection::Title:
|
||||
title = std::make_unique<Title>(renderer, screen, input, asset, options, lang, section);
|
||||
title = std::make_unique<Title>(renderer, screen, input, asset, lang, section);
|
||||
break;
|
||||
case ActiveSection::Game: {
|
||||
const int numPlayers = section->subsection == SUBSECTION_GAME_PLAY_1P ? 1 : 2;
|
||||
game = std::make_unique<Game>(numPlayers, 0, renderer, screen, asset, lang, input, false, options, section);
|
||||
game = std::make_unique<Game>(numPlayers, 0, renderer, screen, asset, lang, input, false, section);
|
||||
break;
|
||||
}
|
||||
case ActiveSection::None:
|
||||
@@ -733,7 +565,7 @@ SDL_AppResult Director::iterate() {
|
||||
#endif
|
||||
|
||||
// Actualiza la visibilidad del cursor del ratón
|
||||
Mouse::updateCursorVisibility(options->videoMode != 0);
|
||||
Mouse::updateCursorVisibility(Options::video.fullscreen);
|
||||
|
||||
// Gestiona las transiciones entre secciones
|
||||
handleSectionTransition();
|
||||
@@ -789,7 +621,7 @@ SDL_AppResult Director::handleEvent(SDL_Event *event) {
|
||||
}
|
||||
|
||||
// Gestiona la visibilidad del cursor según el movimiento del ratón
|
||||
Mouse::handleEvent(*event, options->videoMode != 0);
|
||||
Mouse::handleEvent(*event, Options::video.fullscreen);
|
||||
|
||||
// Reenvía el evento a la sección activa
|
||||
switch (activeSection) {
|
||||
@@ -812,103 +644,3 @@ SDL_AppResult Director::handleEvent(SDL_Event *event) {
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
// Asigna variables a partir de dos cadenas
|
||||
bool Director::setOptions(options_t *options, std::string var, std::string value) {
|
||||
// Indicador de éxito en la asignación
|
||||
bool success = true;
|
||||
|
||||
// Opciones de video
|
||||
if (var == "videoMode") {
|
||||
if (value == "SDL_WINDOW_FULLSCREEN" || value == "SDL_WINDOW_FULLSCREEN_DESKTOP") {
|
||||
options->videoMode = SDL_WINDOW_FULLSCREEN;
|
||||
} else {
|
||||
options->videoMode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if (var == "windowSize") {
|
||||
options->windowSize = std::stoi(value);
|
||||
if ((options->windowSize < 1) || (options->windowSize > 4)) {
|
||||
options->windowSize = 3;
|
||||
}
|
||||
}
|
||||
|
||||
else if (var == "filter") {
|
||||
if (value == "FILTER_LINEAL") {
|
||||
options->filter = FILTER_LINEAL;
|
||||
} else {
|
||||
options->filter = FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
else if (var == "vSync") {
|
||||
options->vSync = stringToBool(value);
|
||||
}
|
||||
|
||||
else if (var == "integerScale") {
|
||||
options->integerScale = stringToBool(value);
|
||||
}
|
||||
|
||||
else if (var == "keepAspect") {
|
||||
options->keepAspect = stringToBool(value);
|
||||
}
|
||||
|
||||
else if (var == "borderEnabled") {
|
||||
options->borderEnabled = stringToBool(value);
|
||||
}
|
||||
|
||||
else if (var == "borderWidth") {
|
||||
options->borderWidth = std::stoi(value);
|
||||
}
|
||||
|
||||
else if (var == "borderHeight") {
|
||||
options->borderHeight = std::stoi(value);
|
||||
}
|
||||
|
||||
// Opciones de GPU / shaders
|
||||
else if (var == "videoGpuAcceleration") {
|
||||
options->videoGpuAcceleration = stringToBool(value);
|
||||
}
|
||||
|
||||
else if (var == "videoGpuPreferredDriver") {
|
||||
options->videoGpuPreferredDriver = value;
|
||||
}
|
||||
|
||||
else if (var == "videoShaderEnabled") {
|
||||
options->videoShaderEnabled = stringToBool(value);
|
||||
}
|
||||
|
||||
else if (var == "videoShaderType") {
|
||||
options->videoShaderType = std::stoi(value);
|
||||
if (options->videoShaderType < 0 || options->videoShaderType > 1) {
|
||||
options->videoShaderType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Opciones varias
|
||||
else if (var == "language") {
|
||||
options->language = std::stoi(value);
|
||||
}
|
||||
|
||||
else if (var == "difficulty") {
|
||||
options->difficulty = std::stoi(value);
|
||||
}
|
||||
|
||||
else if (var == "input0") {
|
||||
options->input[0].deviceType = std::stoi(value);
|
||||
}
|
||||
|
||||
else if (var == "input1") {
|
||||
options->input[1].deviceType = std::stoi(value);
|
||||
}
|
||||
|
||||
// Lineas vacias o que empiezan por comentario
|
||||
else if (var == "" || var.substr(0, 1) == "#") {
|
||||
}
|
||||
|
||||
else {
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
@@ -12,12 +12,8 @@ class Lang;
|
||||
class Logo;
|
||||
class Screen;
|
||||
class Title;
|
||||
struct options_t;
|
||||
struct section_t;
|
||||
|
||||
// Textos
|
||||
constexpr const char *WINDOW_CAPTION = "© 2020 Coffee Crisis — JailDesigner";
|
||||
|
||||
// Secciones activas del Director
|
||||
enum class ActiveSection { None,
|
||||
Logo,
|
||||
@@ -44,7 +40,6 @@ class Director {
|
||||
std::unique_ptr<Game> game;
|
||||
|
||||
// Variables
|
||||
struct options_t *options; // Variable con todas las opciones del programa
|
||||
std::string executablePath; // Path del ejecutable
|
||||
std::string systemFolder; // Carpeta del sistema donde guardar datos
|
||||
|
||||
@@ -57,21 +52,9 @@ class Director {
|
||||
// Inicializa el objeto input
|
||||
void initInput();
|
||||
|
||||
// Inicializa las opciones del programa
|
||||
void initOptions();
|
||||
|
||||
// Asigna variables a partir de dos cadenas
|
||||
bool setOptions(options_t *options, std::string var, std::string value);
|
||||
|
||||
// Crea el indice de ficheros
|
||||
bool setFileList();
|
||||
|
||||
// Carga el fichero de configuración
|
||||
bool loadConfigFile();
|
||||
|
||||
// Guarda el fichero de configuración
|
||||
bool saveConfigFile();
|
||||
|
||||
// Comprueba los parametros del programa
|
||||
void checkProgramArguments(int argc, const char *argv[]);
|
||||
|
||||
|
||||
@@ -5,6 +5,56 @@
|
||||
#include "core/locale/lang.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
// =============================================================================
|
||||
// Defaults per a Options (alineats amb coffee_crisis_arcade_edition).
|
||||
// =============================================================================
|
||||
|
||||
namespace Defaults::Window {
|
||||
constexpr const char *CAPTION = "© 2020 Coffee Crisis — JailDesigner";
|
||||
constexpr int ZOOM = 3;
|
||||
constexpr int MAX_ZOOM = 4;
|
||||
} // namespace Defaults::Window
|
||||
|
||||
namespace Defaults::Video {
|
||||
constexpr SDL_ScaleMode SCALE_MODE = SDL_ScaleMode::SDL_SCALEMODE_NEAREST;
|
||||
constexpr bool FULLSCREEN = false;
|
||||
constexpr bool VSYNC = true;
|
||||
constexpr bool INTEGER_SCALE = true;
|
||||
constexpr bool GPU_ACCELERATION = true;
|
||||
constexpr const char *GPU_PREFERRED_DRIVER = "";
|
||||
constexpr bool SHADER_ENABLED = false;
|
||||
constexpr bool SUPERSAMPLING = false;
|
||||
constexpr bool LINEAR_UPSCALE = false;
|
||||
constexpr int DOWNSCALE_ALGO = 1;
|
||||
} // namespace Defaults::Video
|
||||
|
||||
namespace Defaults::Audio {
|
||||
constexpr bool ENABLED = true;
|
||||
constexpr int VOLUME = 100;
|
||||
} // namespace Defaults::Audio
|
||||
|
||||
namespace Defaults::Music {
|
||||
constexpr bool ENABLED = true;
|
||||
constexpr int VOLUME = 100;
|
||||
} // namespace Defaults::Music
|
||||
|
||||
namespace Defaults::Sound {
|
||||
constexpr bool ENABLED = true;
|
||||
constexpr int VOLUME = 100;
|
||||
} // namespace Defaults::Sound
|
||||
|
||||
namespace Defaults::Loading {
|
||||
constexpr bool SHOW = false;
|
||||
constexpr bool SHOW_RESOURCE_NAME = true;
|
||||
constexpr bool WAIT_FOR_INPUT = false;
|
||||
} // namespace Defaults::Loading
|
||||
|
||||
namespace Defaults::Settings {
|
||||
constexpr int DIFFICULTY = DIFFICULTY_NORMAL;
|
||||
constexpr int LANGUAGE = ba_BA;
|
||||
constexpr palette_e PALETTE = p_zxspectrum;
|
||||
} // namespace Defaults::Settings
|
||||
|
||||
// Tamaño de bloque
|
||||
constexpr int BLOCK = 8;
|
||||
constexpr int HALF_BLOCK = BLOCK / 2;
|
||||
|
||||
@@ -24,18 +24,18 @@
|
||||
#include "game/entities/bullet.h" // for Bullet, BULLET_LEFT, BULLET_RIGHT, BULLE...
|
||||
#include "game/entities/item.h" // for Item, ITEM_COFFEE_MACHINE, ITEM_CLOCK
|
||||
#include "game/entities/player.h" // for Player, DEATH_COUNTER
|
||||
#include "game/options.hpp" // for Options
|
||||
#include "game/ui/menu.h" // for Menu
|
||||
struct JA_Sound_t;
|
||||
|
||||
// Constructor
|
||||
Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *asset, Lang *lang, Input *input, bool demo, options_t *options, section_t *section) {
|
||||
Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *asset, Lang *lang, Input *input, bool demo, section_t *section) {
|
||||
// Copia los punteros
|
||||
this->renderer = renderer;
|
||||
this->screen = screen;
|
||||
this->asset = asset;
|
||||
this->lang = lang;
|
||||
this->input = input;
|
||||
this->options = options;
|
||||
this->section = section;
|
||||
|
||||
// Pasa variables
|
||||
@@ -48,10 +48,10 @@ Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *scr
|
||||
#endif
|
||||
lastStageReached = currentStage;
|
||||
if (numPlayers == 1) { // Si solo juega un jugador, permite jugar tanto con teclado como con mando
|
||||
onePlayerControl = options->input[0].deviceType;
|
||||
options->input[0].deviceType = INPUT_USE_ANY;
|
||||
onePlayerControl = Options::inputs[0].deviceType;
|
||||
Options::inputs[0].deviceType = INPUT_USE_ANY;
|
||||
}
|
||||
difficulty = options->difficulty;
|
||||
difficulty = Options::settings.difficulty;
|
||||
|
||||
// Crea los objetos
|
||||
fade = new Fade(renderer);
|
||||
@@ -96,7 +96,7 @@ Game::~Game() {
|
||||
|
||||
// Restaura el metodo de control
|
||||
if (numPlayers == 1) {
|
||||
options->input[0].deviceType = onePlayerControl;
|
||||
Options::inputs[0].deviceType = onePlayerControl;
|
||||
}
|
||||
|
||||
// Elimina todos los objetos contenidos en vectores (jugadores, balas, etc.)
|
||||
@@ -143,7 +143,7 @@ void Game::init() {
|
||||
|
||||
// Crea los jugadores
|
||||
if (numPlayers == 1) {
|
||||
Player *player = new Player(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, renderer, playerTextures[options->playerSelected], playerAnimations);
|
||||
Player *player = new Player(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, renderer, playerTextures[Options::settings.player_selected], playerAnimations);
|
||||
players.push_back(player);
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ void Game::init() {
|
||||
|
||||
// Carga los recursos necesarios para la sección 'Game'
|
||||
void Game::loadMedia() {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << std::endl
|
||||
<< "** LOADING RESOURCES FOR GAME SECTION" << std::endl;
|
||||
}
|
||||
@@ -433,7 +433,7 @@ void Game::loadMedia() {
|
||||
// Musicas
|
||||
gameMusic = R->getMusic("playing.ogg");
|
||||
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "** RESOURCES FOR GAME SECTION LOADED" << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
@@ -449,14 +449,14 @@ bool Game::loadScoreFile() {
|
||||
|
||||
// El fichero no existe
|
||||
if (file == nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
|
||||
}
|
||||
|
||||
// Creamos el fichero para escritura
|
||||
file = SDL_IOFromFile(p.c_str(), "w+b");
|
||||
if (file != nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "New file (" << filename.c_str() << ") created!" << std::endl;
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ bool Game::loadScoreFile() {
|
||||
// Cerramos el fichero
|
||||
SDL_CloseIO(file);
|
||||
} else {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Error: Unable to create file " << filename.c_str() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
@@ -478,7 +478,7 @@ bool Game::loadScoreFile() {
|
||||
// El fichero existe
|
||||
else {
|
||||
// Cargamos los datos
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Reading file " << filename.c_str() << std::endl;
|
||||
}
|
||||
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
||||
@@ -511,12 +511,12 @@ bool Game::loadDemoFile() {
|
||||
for (int i = 0; i < TOTAL_DEMO_DATA; ++i) {
|
||||
memcpy(&demo.dataFile[i], bytes.data() + i * sizeof(demoKeys_t), sizeof(demoKeys_t));
|
||||
}
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Demo data loaded (" << bytes.size() << " bytes)" << std::endl;
|
||||
}
|
||||
} else {
|
||||
// Si no hay datos (bytes vacíos o tamaño inválido), inicializamos a cero.
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Warning: demo data missing or too small, initializing to zero" << std::endl;
|
||||
}
|
||||
for (int i = 0; i < TOTAL_DEMO_DATA; ++i) {
|
||||
@@ -544,14 +544,14 @@ bool Game::saveScoreFile() {
|
||||
SDL_WriteIO(file, &scoreDataFile[i], sizeof(Uint32));
|
||||
}
|
||||
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Writing file " << filename.c_str() << std::endl;
|
||||
}
|
||||
|
||||
// Cerramos el fichero
|
||||
SDL_CloseIO(file);
|
||||
} else {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Error: Unable to save " << filename.c_str() << " file! " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -571,14 +571,14 @@ bool Game::saveDemoFile() {
|
||||
SDL_WriteIO(file, &demo.dataFile[i], sizeof(demoKeys_t));
|
||||
}
|
||||
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Writing file " << filename.c_str() << std::endl;
|
||||
}
|
||||
|
||||
// Cerramos el fichero
|
||||
SDL_CloseIO(file);
|
||||
} else {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Error: Unable to save " << filename.c_str() << " file! " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -2600,12 +2600,12 @@ void Game::checkGameInput() {
|
||||
for (auto player : players) {
|
||||
if (player->isAlive()) {
|
||||
// Input a la izquierda
|
||||
if (input->checkInput(input_left, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id)) {
|
||||
if (input->checkInput(input_left, REPEAT_TRUE, Options::inputs[i].deviceType, Options::inputs[i].id)) {
|
||||
player->setInput(input_left);
|
||||
demo.keys.left = 1;
|
||||
} else {
|
||||
// Input a la derecha
|
||||
if (input->checkInput(input_right, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id)) {
|
||||
if (input->checkInput(input_right, REPEAT_TRUE, Options::inputs[i].deviceType, Options::inputs[i].id)) {
|
||||
player->setInput(input_right);
|
||||
demo.keys.right = 1;
|
||||
} else {
|
||||
@@ -2615,7 +2615,7 @@ void Game::checkGameInput() {
|
||||
}
|
||||
}
|
||||
// Comprueba el input de disparar al centro
|
||||
if (input->checkInput(input_fire_center, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id)) {
|
||||
if (input->checkInput(input_fire_center, REPEAT_TRUE, Options::inputs[i].deviceType, Options::inputs[i].id)) {
|
||||
if (player->canFire()) {
|
||||
player->setInput(input_fire_center);
|
||||
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_UP, player->isPowerUp(), i);
|
||||
@@ -2629,7 +2629,7 @@ void Game::checkGameInput() {
|
||||
}
|
||||
|
||||
// Comprueba el input de disparar a la izquierda
|
||||
if (input->checkInput(input_fire_left, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id)) {
|
||||
if (input->checkInput(input_fire_left, REPEAT_TRUE, Options::inputs[i].deviceType, Options::inputs[i].id)) {
|
||||
if (player->canFire()) {
|
||||
player->setInput(input_fire_left);
|
||||
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_LEFT, player->isPowerUp(), i);
|
||||
@@ -2643,7 +2643,7 @@ void Game::checkGameInput() {
|
||||
}
|
||||
|
||||
// Comprueba el input de disparar a la derecha
|
||||
if (input->checkInput(input_fire_right, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id)) {
|
||||
if (input->checkInput(input_fire_right, REPEAT_TRUE, Options::inputs[i].deviceType, Options::inputs[i].id)) {
|
||||
if (player->canFire()) {
|
||||
player->setInput(input_fire_right);
|
||||
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_RIGHT, player->isPowerUp(), i);
|
||||
@@ -2657,7 +2657,7 @@ void Game::checkGameInput() {
|
||||
}
|
||||
|
||||
// Comprueba el input de pausa
|
||||
if (input->checkInput(input_pause, REPEAT_FALSE, options->input[i].deviceType, options->input[i].id)) {
|
||||
if (input->checkInput(input_pause, REPEAT_FALSE, Options::inputs[i].deviceType, Options::inputs[i].id)) {
|
||||
section->subsection = SUBSECTION_GAME_PAUSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,6 @@ class Game {
|
||||
Uint8 difficulty; // Dificultad del juego
|
||||
float difficultyScoreMultiplier; // Multiplicador de puntos en función de la dificultad
|
||||
color_t difficultyColor; // Color asociado a la dificultad
|
||||
struct options_t *options; // Variable con todas las variables de las opciones del programa
|
||||
Uint8 onePlayerControl; // Variable para almacenar el valor de las opciones
|
||||
enemyFormation_t enemyFormation[NUMBER_OF_ENEMY_FORMATIONS]; // Vector con todas las formaciones enemigas
|
||||
enemyPool_t enemyPool[10]; // Variable con los diferentes conjuntos de formaciones enemigas
|
||||
@@ -546,7 +545,7 @@ class Game {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *asset, Lang *lang, Input *input, bool demo, options_t *options, section_t *section);
|
||||
Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *asset, Lang *lang, Input *input, bool demo, section_t *section);
|
||||
|
||||
// Destructor
|
||||
~Game();
|
||||
|
||||
342
source/game/options.cpp
Normal file
342
source/game/options.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
#include "game/options.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "core/input/input.h" // for INPUT_USE_KEYBOARD, INPUT_USE_GAMECONTROLLER
|
||||
#include "core/locale/lang.h" // for MAX_LANGUAGES, en_UK
|
||||
#include "external/fkyaml_node.hpp" // for fkyaml::node
|
||||
#include "utils/utils.h" // for boolToString
|
||||
|
||||
namespace Options {
|
||||
|
||||
// --- Variables globales ---
|
||||
Window window;
|
||||
Video video;
|
||||
Audio audio;
|
||||
Loading loading;
|
||||
Settings settings;
|
||||
std::vector<input_t> inputs;
|
||||
|
||||
// --- Helpers locals ---
|
||||
namespace {
|
||||
void parseBoolField(const fkyaml::node &node, const std::string &key, bool &target) {
|
||||
if (node.contains(key)) {
|
||||
try {
|
||||
target = node[key].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
void parseIntField(const fkyaml::node &node, const std::string &key, int &target) {
|
||||
if (node.contains(key)) {
|
||||
try {
|
||||
target = node[key].get_value<int>();
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
void parseStringField(const fkyaml::node &node, const std::string &key, std::string &target) {
|
||||
if (node.contains(key)) {
|
||||
try {
|
||||
target = node[key].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
void loadWindowFromYaml(const fkyaml::node &yaml) {
|
||||
if (!yaml.contains("window")) { return; }
|
||||
const auto &win = yaml["window"];
|
||||
parseIntField(win, "zoom", window.zoom);
|
||||
if (window.zoom < 1 || window.zoom > window.max_zoom) {
|
||||
window.zoom = Defaults::Window::ZOOM;
|
||||
}
|
||||
}
|
||||
|
||||
void loadVideoFromYaml(const fkyaml::node &yaml) {
|
||||
if (!yaml.contains("video")) { return; }
|
||||
const auto &vid = yaml["video"];
|
||||
|
||||
parseBoolField(vid, "fullscreen", video.fullscreen);
|
||||
parseBoolField(vid, "vsync", video.vsync);
|
||||
parseBoolField(vid, "integer_scale", video.integer_scale);
|
||||
if (vid.contains("scale_mode")) {
|
||||
try {
|
||||
video.scale_mode = static_cast<SDL_ScaleMode>(vid["scale_mode"].get_value<int>());
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
if (vid.contains("gpu")) {
|
||||
const auto &gpu = vid["gpu"];
|
||||
parseBoolField(gpu, "acceleration", video.gpu.acceleration);
|
||||
parseStringField(gpu, "preferred_driver", video.gpu.preferred_driver);
|
||||
}
|
||||
|
||||
if (vid.contains("supersampling")) {
|
||||
const auto &ss = vid["supersampling"];
|
||||
parseBoolField(ss, "enabled", video.supersampling.enabled);
|
||||
parseBoolField(ss, "linear_upscale", video.supersampling.linear_upscale);
|
||||
parseIntField(ss, "downscale_algo", video.supersampling.downscale_algo);
|
||||
}
|
||||
|
||||
if (vid.contains("shader")) {
|
||||
const auto &sh = vid["shader"];
|
||||
parseBoolField(sh, "enabled", video.shader.enabled);
|
||||
if (sh.contains("current_shader")) {
|
||||
try {
|
||||
auto s = sh["current_shader"].get_value<std::string>();
|
||||
video.shader.current_shader = (s == "crtpi" || s == "CRTPI")
|
||||
? Rendering::ShaderType::CRTPI
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
} catch (...) {}
|
||||
}
|
||||
parseStringField(sh, "current_postfx_preset", video.shader.current_postfx_preset_name);
|
||||
parseStringField(sh, "current_crtpi_preset", video.shader.current_crtpi_preset_name);
|
||||
}
|
||||
}
|
||||
|
||||
void loadAudioFromYaml(const fkyaml::node &yaml) {
|
||||
if (!yaml.contains("audio")) { return; }
|
||||
const auto &aud = yaml["audio"];
|
||||
|
||||
parseBoolField(aud, "enabled", audio.enabled);
|
||||
if (aud.contains("volume")) {
|
||||
try {
|
||||
audio.volume = std::clamp(aud["volume"].get_value<int>(), 0, 100);
|
||||
} catch (...) {}
|
||||
}
|
||||
if (aud.contains("music")) {
|
||||
const auto &mus = aud["music"];
|
||||
parseBoolField(mus, "enabled", audio.music.enabled);
|
||||
if (mus.contains("volume")) {
|
||||
try {
|
||||
audio.music.volume = std::clamp(mus["volume"].get_value<int>(), 0, 100);
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
if (aud.contains("sound")) {
|
||||
const auto &snd = aud["sound"];
|
||||
parseBoolField(snd, "enabled", audio.sound.enabled);
|
||||
if (snd.contains("volume")) {
|
||||
try {
|
||||
audio.sound.volume = std::clamp(snd["volume"].get_value<int>(), 0, 100);
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadLoadingFromYaml(const fkyaml::node &yaml) {
|
||||
if (!yaml.contains("loading")) { return; }
|
||||
const auto &ld = yaml["loading"];
|
||||
parseBoolField(ld, "show", loading.show);
|
||||
parseBoolField(ld, "show_resource_name", loading.show_resource_name);
|
||||
parseBoolField(ld, "wait_for_input", loading.wait_for_input);
|
||||
}
|
||||
|
||||
void loadSettingsFromYaml(const fkyaml::node &yaml) {
|
||||
if (!yaml.contains("settings")) { return; }
|
||||
const auto &st = yaml["settings"];
|
||||
parseIntField(st, "difficulty", settings.difficulty);
|
||||
parseIntField(st, "language", settings.language);
|
||||
if (settings.language < 0 || settings.language > MAX_LANGUAGES) {
|
||||
settings.language = en_UK;
|
||||
}
|
||||
if (st.contains("palette")) {
|
||||
try {
|
||||
settings.palette = static_cast<palette_e>(st["palette"].get_value<int>());
|
||||
} catch (...) {}
|
||||
}
|
||||
parseIntField(st, "player_selected", settings.player_selected);
|
||||
}
|
||||
|
||||
void loadInputsFromYaml(const fkyaml::node &yaml) {
|
||||
if (!yaml.contains("input") || inputs.size() < 2) { return; }
|
||||
const auto &ins = yaml["input"];
|
||||
size_t i = 0;
|
||||
for (const auto &entry : ins) {
|
||||
if (i >= inputs.size()) { break; }
|
||||
if (entry.contains("device_type")) {
|
||||
try {
|
||||
inputs[i].deviceType = static_cast<Uint8>(entry["device_type"].get_value<int>());
|
||||
} catch (...) {}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// --- Funciones públiques ---
|
||||
|
||||
void setConfigFile(const std::string &file_path) {
|
||||
settings.config_file = file_path;
|
||||
}
|
||||
|
||||
void init() {
|
||||
// Reinicia structs a defaults (els member-initializers ho fan sols).
|
||||
window = Window{};
|
||||
video = Video{};
|
||||
audio = Audio{};
|
||||
loading = Loading{};
|
||||
|
||||
// Preserva config_file si ja s'ha establert abans.
|
||||
const std::string PREV_CONFIG_FILE = settings.config_file;
|
||||
settings = Settings{};
|
||||
settings.config_file = PREV_CONFIG_FILE;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// En Emscripten la ventana la gestiona el navegador
|
||||
window.zoom = 4;
|
||||
video.fullscreen = false;
|
||||
video.integer_scale = true;
|
||||
#endif
|
||||
|
||||
// Dispositius d'entrada per defecte
|
||||
inputs.clear();
|
||||
input_t kb;
|
||||
kb.id = 0;
|
||||
kb.name = "KEYBOARD";
|
||||
kb.deviceType = INPUT_USE_KEYBOARD;
|
||||
inputs.push_back(kb);
|
||||
|
||||
input_t gc;
|
||||
gc.id = 0;
|
||||
gc.name = "GAME CONTROLLER";
|
||||
gc.deviceType = INPUT_USE_GAMECONTROLLER;
|
||||
inputs.push_back(gc);
|
||||
}
|
||||
|
||||
auto loadFromFile() -> bool {
|
||||
init();
|
||||
|
||||
std::ifstream file(settings.config_file);
|
||||
if (!file.is_open()) {
|
||||
// Primera execució: crea el YAML amb defaults.
|
||||
return saveToFile();
|
||||
}
|
||||
|
||||
const std::string CONTENT((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(CONTENT);
|
||||
|
||||
int file_version = 0;
|
||||
if (yaml.contains("config_version")) {
|
||||
try {
|
||||
file_version = yaml["config_version"].get_value<int>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (file_version != Settings::CURRENT_CONFIG_VERSION) {
|
||||
std::cout << "Config version " << file_version
|
||||
<< " != expected " << Settings::CURRENT_CONFIG_VERSION
|
||||
<< ". Recreating defaults.\n";
|
||||
init();
|
||||
return saveToFile();
|
||||
}
|
||||
|
||||
loadWindowFromYaml(yaml);
|
||||
loadVideoFromYaml(yaml);
|
||||
loadAudioFromYaml(yaml);
|
||||
loadLoadingFromYaml(yaml);
|
||||
loadSettingsFromYaml(yaml);
|
||||
loadInputsFromYaml(yaml);
|
||||
|
||||
} catch (const fkyaml::exception &e) {
|
||||
std::cout << "Error parsing YAML config: " << e.what() << ". Using defaults.\n";
|
||||
init();
|
||||
return saveToFile();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto saveToFile() -> bool {
|
||||
if (settings.config_file.empty()) { return false; }
|
||||
std::ofstream file(settings.config_file);
|
||||
if (!file.is_open()) {
|
||||
std::cout << "Error: " << settings.config_file << " can't be opened for writing\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
file << "# Coffee Crisis - Configuration file\n";
|
||||
file << "# Auto-generated, managed by the game.\n\n";
|
||||
|
||||
file << "config_version: " << settings.config_version << "\n\n";
|
||||
|
||||
// WINDOW
|
||||
file << "# WINDOW\n";
|
||||
file << "window:\n";
|
||||
file << " zoom: " << window.zoom << "\n";
|
||||
file << " max_zoom: " << window.max_zoom << "\n\n";
|
||||
|
||||
// VIDEO
|
||||
file << "# VIDEO\n";
|
||||
file << "video:\n";
|
||||
file << " fullscreen: " << boolToString(video.fullscreen) << "\n";
|
||||
file << " vsync: " << boolToString(video.vsync) << "\n";
|
||||
file << " integer_scale: " << boolToString(video.integer_scale) << "\n";
|
||||
file << " scale_mode: " << static_cast<int>(video.scale_mode)
|
||||
<< " # " << static_cast<int>(SDL_SCALEMODE_NEAREST) << ": nearest, "
|
||||
<< static_cast<int>(SDL_SCALEMODE_LINEAR) << ": linear\n";
|
||||
file << " gpu:\n";
|
||||
file << " acceleration: " << boolToString(video.gpu.acceleration) << "\n";
|
||||
file << " preferred_driver: \"" << video.gpu.preferred_driver << "\"\n";
|
||||
file << " supersampling:\n";
|
||||
file << " enabled: " << boolToString(video.supersampling.enabled) << "\n";
|
||||
file << " linear_upscale: " << boolToString(video.supersampling.linear_upscale) << "\n";
|
||||
file << " downscale_algo: " << video.supersampling.downscale_algo << "\n";
|
||||
file << " shader:\n";
|
||||
file << " enabled: " << boolToString(video.shader.enabled) << "\n";
|
||||
file << " current_shader: "
|
||||
<< (video.shader.current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx")
|
||||
<< "\n";
|
||||
file << " current_postfx_preset: \"" << video.shader.current_postfx_preset_name << "\"\n";
|
||||
file << " current_crtpi_preset: \"" << video.shader.current_crtpi_preset_name << "\"\n\n";
|
||||
|
||||
// AUDIO
|
||||
file << "# AUDIO (volume range: 0..100)\n";
|
||||
file << "audio:\n";
|
||||
file << " enabled: " << boolToString(audio.enabled) << "\n";
|
||||
file << " volume: " << audio.volume << "\n";
|
||||
file << " music:\n";
|
||||
file << " enabled: " << boolToString(audio.music.enabled) << "\n";
|
||||
file << " volume: " << audio.music.volume << "\n";
|
||||
file << " sound:\n";
|
||||
file << " enabled: " << boolToString(audio.sound.enabled) << "\n";
|
||||
file << " volume: " << audio.sound.volume << "\n\n";
|
||||
|
||||
// LOADING
|
||||
file << "# LOADING SCREEN\n";
|
||||
file << "loading:\n";
|
||||
file << " show: " << boolToString(loading.show) << "\n";
|
||||
file << " show_resource_name: " << boolToString(loading.show_resource_name) << "\n";
|
||||
file << " wait_for_input: " << boolToString(loading.wait_for_input) << "\n\n";
|
||||
|
||||
// SETTINGS
|
||||
file << "# SETTINGS\n";
|
||||
file << "settings:\n";
|
||||
file << " difficulty: " << settings.difficulty << "\n";
|
||||
file << " language: " << settings.language << "\n";
|
||||
file << " palette: " << static_cast<int>(settings.palette) << "\n";
|
||||
file << " player_selected: " << settings.player_selected << "\n\n";
|
||||
|
||||
// INPUT
|
||||
file << "# INPUT DEVICES (device_type: "
|
||||
<< static_cast<int>(INPUT_USE_KEYBOARD) << "=KEYBOARD, "
|
||||
<< static_cast<int>(INPUT_USE_GAMECONTROLLER) << "=GAMECONTROLLER)\n";
|
||||
file << "input:\n";
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
file << " - slot: " << i << "\n";
|
||||
file << " device_type: " << static_cast<int>(inputs[i].deviceType) << "\n";
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Options
|
||||
105
source/game/options.hpp
Normal file
105
source/game/options.hpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "core/rendering/shader_backend.hpp" // for Rendering::ShaderType
|
||||
#include "game/defaults.hpp"
|
||||
#include "utils/utils.h" // for input_t, palette_e
|
||||
|
||||
// =============================================================================
|
||||
// Opciones del programa, alineades amb coffee_crisis_arcade_edition.
|
||||
// L'estat viu en globals dins el namespace Options:: (window, video, audio,
|
||||
// loading, settings, inputs). La persistència usa fkyaml i es guarda a
|
||||
// config.yaml dins la carpeta de configuració del sistema.
|
||||
// =============================================================================
|
||||
|
||||
namespace Options {
|
||||
|
||||
struct Window {
|
||||
std::string caption = Defaults::Window::CAPTION;
|
||||
int zoom = Defaults::Window::ZOOM;
|
||||
int max_zoom = Defaults::Window::MAX_ZOOM;
|
||||
};
|
||||
|
||||
struct GPU {
|
||||
bool acceleration = Defaults::Video::GPU_ACCELERATION;
|
||||
std::string preferred_driver = Defaults::Video::GPU_PREFERRED_DRIVER;
|
||||
};
|
||||
|
||||
struct Supersampling {
|
||||
bool enabled = Defaults::Video::SUPERSAMPLING;
|
||||
bool linear_upscale = Defaults::Video::LINEAR_UPSCALE;
|
||||
int downscale_algo = Defaults::Video::DOWNSCALE_ALGO;
|
||||
};
|
||||
|
||||
struct ShaderConfig {
|
||||
bool enabled = Defaults::Video::SHADER_ENABLED;
|
||||
Rendering::ShaderType current_shader = Rendering::ShaderType::POSTFX;
|
||||
std::string current_postfx_preset_name = "CRT";
|
||||
std::string current_crtpi_preset_name = "Default";
|
||||
int current_postfx_preset = 0;
|
||||
int current_crtpi_preset = 0;
|
||||
};
|
||||
|
||||
struct Video {
|
||||
SDL_ScaleMode scale_mode = Defaults::Video::SCALE_MODE;
|
||||
bool fullscreen = Defaults::Video::FULLSCREEN;
|
||||
bool vsync = Defaults::Video::VSYNC;
|
||||
bool integer_scale = Defaults::Video::INTEGER_SCALE;
|
||||
GPU gpu;
|
||||
Supersampling supersampling;
|
||||
ShaderConfig shader;
|
||||
};
|
||||
|
||||
struct Music {
|
||||
bool enabled = Defaults::Music::ENABLED;
|
||||
int volume = Defaults::Music::VOLUME;
|
||||
};
|
||||
|
||||
struct Sound {
|
||||
bool enabled = Defaults::Sound::ENABLED;
|
||||
int volume = Defaults::Sound::VOLUME;
|
||||
};
|
||||
|
||||
struct Audio {
|
||||
bool enabled = Defaults::Audio::ENABLED;
|
||||
int volume = Defaults::Audio::VOLUME;
|
||||
Music music;
|
||||
Sound sound;
|
||||
};
|
||||
|
||||
struct Loading {
|
||||
bool show = Defaults::Loading::SHOW;
|
||||
bool show_resource_name = Defaults::Loading::SHOW_RESOURCE_NAME;
|
||||
bool wait_for_input = Defaults::Loading::WAIT_FOR_INPUT;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
static constexpr int CURRENT_CONFIG_VERSION = 1;
|
||||
int config_version = CURRENT_CONFIG_VERSION;
|
||||
int difficulty = Defaults::Settings::DIFFICULTY;
|
||||
int language = Defaults::Settings::LANGUAGE;
|
||||
palette_e palette = Defaults::Settings::PALETTE;
|
||||
bool console = false;
|
||||
int player_selected = 0;
|
||||
std::string config_file;
|
||||
};
|
||||
|
||||
// --- Variables globales ---
|
||||
extern Window window;
|
||||
extern Video video;
|
||||
extern Audio audio;
|
||||
extern Loading loading;
|
||||
extern Settings settings;
|
||||
extern std::vector<input_t> inputs; // [0]=KEYBOARD, [1]=GAMECONTROLLER per defecte
|
||||
|
||||
// --- Funciones ---
|
||||
void init(); // Reinicia a defaults i omple `inputs`
|
||||
void setConfigFile(const std::string &file_path); // Ruta del config.yaml
|
||||
auto loadFromFile() -> bool; // Carrega el YAML; si no existeix, crea'l amb defaults
|
||||
auto saveToFile() -> bool; // Guarda el YAML
|
||||
|
||||
} // namespace Options
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "core/locale/lang.h" // for Lang, ba_BA, en_UK, es_ES
|
||||
#include "core/rendering/animatedsprite.h" // for AnimatedSprite
|
||||
#include "core/rendering/fade.h" // for Fade
|
||||
#include "core/rendering/screen.h" // for Screen, FILTER_LINEAL, FILTER_NEAREST
|
||||
#include "core/rendering/screen.h" // for Screen
|
||||
#include "core/rendering/smartsprite.h" // for SmartSprite
|
||||
#include "core/rendering/sprite.h" // for Sprite
|
||||
#include "core/rendering/text.h" // for Text, TXT_CENTER, TXT_SHADOW
|
||||
@@ -20,16 +20,16 @@
|
||||
#include "core/resources/resource.h"
|
||||
#include "game/defaults.hpp" // for GAMECANVAS_CENTER_X, SECTION_PROG_QUIT
|
||||
#include "game/game.h" // for Game
|
||||
#include "game/options.hpp" // for Options
|
||||
#include "game/ui/menu.h" // for Menu
|
||||
|
||||
// Constructor
|
||||
Title::Title(SDL_Renderer *renderer, Screen *screen, Input *input, Asset *asset, options_t *options, Lang *lang, section_t *section) {
|
||||
Title::Title(SDL_Renderer *renderer, Screen *screen, Input *input, Asset *asset, Lang *lang, section_t *section) {
|
||||
// Copia las direcciones de los punteros
|
||||
this->renderer = renderer;
|
||||
this->screen = screen;
|
||||
this->input = input;
|
||||
this->asset = asset;
|
||||
this->options = options;
|
||||
this->lang = lang;
|
||||
this->section = section;
|
||||
|
||||
@@ -113,18 +113,18 @@ void Title::init() {
|
||||
demoThenInstructions = false;
|
||||
|
||||
// Pone valores por defecto a las opciones de control
|
||||
options->input.clear();
|
||||
Options::inputs.clear();
|
||||
|
||||
input_t i;
|
||||
i.id = 0;
|
||||
i.name = "KEYBOARD";
|
||||
i.deviceType = INPUT_USE_KEYBOARD;
|
||||
options->input.push_back(i);
|
||||
Options::inputs.push_back(i);
|
||||
|
||||
i.id = 0;
|
||||
i.name = "GAME CONTROLLER";
|
||||
i.deviceType = INPUT_USE_GAMECONTROLLER;
|
||||
options->input.push_back(i);
|
||||
Options::inputs.push_back(i);
|
||||
|
||||
// Comprueba si hay mandos conectados
|
||||
checkInputDevices();
|
||||
@@ -136,9 +136,9 @@ void Title::init() {
|
||||
|
||||
// Si ha encontrado un mando se lo asigna al segundo jugador
|
||||
if (input->gameControllerFound()) {
|
||||
options->input[1].id = availableInputDevices[deviceIndex[1]].id;
|
||||
options->input[1].name = availableInputDevices[deviceIndex[1]].name;
|
||||
options->input[1].deviceType = availableInputDevices[deviceIndex[1]].deviceType;
|
||||
Options::inputs[1].id = availableInputDevices[deviceIndex[1]].id;
|
||||
Options::inputs[1].name = availableInputDevices[deviceIndex[1]].name;
|
||||
Options::inputs[1].deviceType = availableInputDevices[deviceIndex[1]].deviceType;
|
||||
} else { // Si no ha encontrado un mando, deshabilita la opción de jugar a 2 jugadores
|
||||
menu.title->setSelectable(1, false);
|
||||
menu.title->setGreyed(1, true);
|
||||
@@ -347,7 +347,10 @@ void Title::update() {
|
||||
|
||||
case 2: // OPTIONS
|
||||
menu.active = menu.options;
|
||||
optionsPrevious = *options;
|
||||
prevVideo = Options::video;
|
||||
prevWindow = Options::window;
|
||||
prevSettings = Options::settings;
|
||||
prevInputs = Options::inputs;
|
||||
break;
|
||||
|
||||
case 3: // QUIT
|
||||
@@ -369,13 +372,13 @@ void Title::update() {
|
||||
|
||||
case 1: // BAL1
|
||||
postFade = 0;
|
||||
options->playerSelected = 0;
|
||||
Options::settings.player_selected = 0;
|
||||
fade->activateFade();
|
||||
break;
|
||||
|
||||
case 2: // AROUNDER
|
||||
postFade = 0;
|
||||
options->playerSelected = 1;
|
||||
Options::settings.player_selected = 1;
|
||||
fade->activateFade();
|
||||
break;
|
||||
|
||||
@@ -393,12 +396,12 @@ void Title::update() {
|
||||
if (menu.active->getName() == "OPTIONS") {
|
||||
switch (menu.active->getItemSelected()) {
|
||||
case 0: // Difficulty
|
||||
if (options->difficulty == DIFFICULTY_EASY)
|
||||
options->difficulty = DIFFICULTY_NORMAL;
|
||||
else if (options->difficulty == DIFFICULTY_NORMAL)
|
||||
options->difficulty = DIFFICULTY_HARD;
|
||||
if (Options::settings.difficulty == DIFFICULTY_EASY)
|
||||
Options::settings.difficulty = DIFFICULTY_NORMAL;
|
||||
else if (Options::settings.difficulty == DIFFICULTY_NORMAL)
|
||||
Options::settings.difficulty = DIFFICULTY_HARD;
|
||||
else
|
||||
options->difficulty = DIFFICULTY_EASY;
|
||||
Options::settings.difficulty = DIFFICULTY_EASY;
|
||||
updateMenuLabels();
|
||||
break;
|
||||
|
||||
@@ -413,15 +416,15 @@ void Title::update() {
|
||||
break;
|
||||
|
||||
case 5: // Language
|
||||
options->language++;
|
||||
if (options->language == 3)
|
||||
options->language = 0;
|
||||
Options::settings.language++;
|
||||
if (Options::settings.language == 3)
|
||||
Options::settings.language = 0;
|
||||
updateMenuLabels();
|
||||
break;
|
||||
|
||||
case 6: // Display mode
|
||||
switchFullScreenModeVar();
|
||||
if (options->videoMode != 0) {
|
||||
if (Options::video.fullscreen) {
|
||||
menu.options->setSelectable(8, false);
|
||||
menu.options->setGreyed(8, true);
|
||||
} else {
|
||||
@@ -432,27 +435,23 @@ void Title::update() {
|
||||
break;
|
||||
|
||||
case 8: // Windows size
|
||||
options->windowSize++;
|
||||
if (options->windowSize == 5)
|
||||
options->windowSize = 1;
|
||||
Options::window.zoom++;
|
||||
if (Options::window.zoom > Options::window.max_zoom)
|
||||
Options::window.zoom = 1;
|
||||
updateMenuLabels();
|
||||
break;
|
||||
|
||||
case 9: // FILTER
|
||||
if (options->filter == FILTER_LINEAL)
|
||||
options->filter = FILTER_NEAREST;
|
||||
else
|
||||
options->filter = FILTER_LINEAL;
|
||||
Texture::setGlobalScaleMode(options->filter == FILTER_NEAREST ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR);
|
||||
case 9: // Scale mode
|
||||
Options::video.scale_mode = (Options::video.scale_mode == SDL_SCALEMODE_NEAREST)
|
||||
? SDL_SCALEMODE_LINEAR
|
||||
: SDL_SCALEMODE_NEAREST;
|
||||
Texture::setGlobalScaleMode(Options::video.scale_mode);
|
||||
reLoadTextures();
|
||||
updateMenuLabels();
|
||||
break;
|
||||
|
||||
case 10: // VSYNC
|
||||
if (options->vSync)
|
||||
options->vSync = false;
|
||||
else
|
||||
options->vSync = true;
|
||||
Options::video.vsync = !Options::video.vsync;
|
||||
updateMenuLabels();
|
||||
break;
|
||||
|
||||
@@ -467,7 +466,10 @@ void Title::update() {
|
||||
break;
|
||||
|
||||
case 13: // CANCEL
|
||||
options = &optionsPrevious;
|
||||
Options::video = prevVideo;
|
||||
Options::window = prevWindow;
|
||||
Options::settings = prevSettings;
|
||||
Options::inputs = prevInputs;
|
||||
updateMenuLabels();
|
||||
menu.active->reset();
|
||||
menu.active = menu.title;
|
||||
@@ -682,25 +684,14 @@ void Title::updateBG() {
|
||||
|
||||
// Cambia el valor de la variable de modo de pantalla completa
|
||||
void Title::switchFullScreenModeVar() {
|
||||
switch (options->videoMode) {
|
||||
case 0:
|
||||
options->videoMode = SDL_WINDOW_FULLSCREEN;
|
||||
break;
|
||||
case SDL_WINDOW_FULLSCREEN:
|
||||
options->videoMode = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
options->videoMode = 0;
|
||||
break;
|
||||
}
|
||||
Options::video.fullscreen = !Options::video.fullscreen;
|
||||
}
|
||||
|
||||
// Actualiza los elementos de los menus
|
||||
void Title::updateMenuLabels() {
|
||||
int i = 0;
|
||||
// DIFFICULTY
|
||||
switch (options->difficulty) {
|
||||
switch (Options::settings.difficulty) {
|
||||
case DIFFICULTY_EASY:
|
||||
menu.options->setItemCaption(i, lang->getText(59) + ": " + lang->getText(66)); // EASY
|
||||
break;
|
||||
@@ -724,7 +715,7 @@ void Title::updateMenuLabels() {
|
||||
|
||||
i++;
|
||||
// PLAYER 1 CONTROLS - OPTIONS
|
||||
switch (options->input[0].deviceType) {
|
||||
switch (Options::inputs[0].deviceType) {
|
||||
case INPUT_USE_KEYBOARD:
|
||||
menu.options->setItemCaption(i, lang->getText(69)); // KEYBOARD
|
||||
menu.options->setGreyed(i, false);
|
||||
@@ -736,7 +727,7 @@ void Title::updateMenuLabels() {
|
||||
menu.options->setGreyed(i, true);
|
||||
else {
|
||||
menu.options->setGreyed(i, false);
|
||||
menu.options->setItemCaption(i, options->input[0].name);
|
||||
menu.options->setItemCaption(i, Options::inputs[0].name);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -751,7 +742,7 @@ void Title::updateMenuLabels() {
|
||||
|
||||
i++;
|
||||
// PLAYER 2 CONTROLS - OPTIONS
|
||||
switch (options->input[1].deviceType) {
|
||||
switch (Options::inputs[1].deviceType) {
|
||||
case INPUT_USE_KEYBOARD:
|
||||
menu.options->setItemCaption(i, lang->getText(69)); // KEYBOARD
|
||||
menu.options->setGreyed(i, false);
|
||||
@@ -763,7 +754,7 @@ void Title::updateMenuLabels() {
|
||||
menu.options->setGreyed(i, true);
|
||||
else {
|
||||
menu.options->setGreyed(i, false);
|
||||
menu.options->setItemCaption(i, options->input[1].name);
|
||||
menu.options->setItemCaption(i, Options::inputs[1].name);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -774,7 +765,7 @@ void Title::updateMenuLabels() {
|
||||
|
||||
i++;
|
||||
// LANGUAGE
|
||||
switch (options->language) {
|
||||
switch (Options::settings.language) {
|
||||
case es_ES:
|
||||
menu.options->setItemCaption(i, lang->getText(8) + ": " + lang->getText(24)); // SPANISH
|
||||
break;
|
||||
@@ -798,34 +789,22 @@ void Title::updateMenuLabels() {
|
||||
|
||||
i++;
|
||||
// DISPLAY MODE - OPTIONS
|
||||
switch (options->videoMode) {
|
||||
case 0:
|
||||
menu.options->setItemCaption(i, lang->getText(4)); // WINDOW
|
||||
break;
|
||||
|
||||
case SDL_WINDOW_FULLSCREEN:
|
||||
menu.options->setItemCaption(i, lang->getText(5)); // FULLSCREEN
|
||||
break;
|
||||
|
||||
default:
|
||||
menu.options->setItemCaption(i, lang->getText(4)); // WINDOW
|
||||
break;
|
||||
}
|
||||
menu.options->setItemCaption(i, Options::video.fullscreen ? lang->getText(5) : lang->getText(4));
|
||||
|
||||
i++;
|
||||
// WINDOW SIZE
|
||||
menu.options->setItemCaption(i, lang->getText(7) + " x" + std::to_string(options->windowSize)); // WINDOW SIZE
|
||||
menu.options->setItemCaption(i, lang->getText(7) + " x" + std::to_string(Options::window.zoom)); // WINDOW SIZE
|
||||
|
||||
i++;
|
||||
// FILTER
|
||||
if (options->filter == FILTER_LINEAL)
|
||||
// SCALE MODE
|
||||
if (Options::video.scale_mode == SDL_SCALEMODE_LINEAR)
|
||||
menu.options->setItemCaption(i, lang->getText(60) + ": " + lang->getText(71)); // BILINEAL
|
||||
else
|
||||
menu.options->setItemCaption(i, lang->getText(60) + ": " + lang->getText(72)); // LINEAL
|
||||
|
||||
i++;
|
||||
// VSYNC
|
||||
if (options->vSync)
|
||||
if (Options::video.vsync)
|
||||
menu.options->setItemCaption(i, lang->getText(61) + ": " + lang->getText(73)); // ON
|
||||
else
|
||||
menu.options->setItemCaption(i, lang->getText(61) + ": " + lang->getText(74)); // OFF
|
||||
@@ -887,9 +866,11 @@ void Title::updateMenuLabels() {
|
||||
|
||||
// Aplica las opciones de menu seleccionadas
|
||||
void Title::applyOptions() {
|
||||
screen->setVideoMode(options->videoMode != 0);
|
||||
screen->setVideoMode(Options::video.fullscreen);
|
||||
screen->setWindowZoom(Options::window.zoom);
|
||||
screen->setVSync(Options::video.vsync);
|
||||
|
||||
lang->setLang(options->language);
|
||||
lang->setLang(Options::settings.language);
|
||||
|
||||
updateMenuLabels();
|
||||
createTiledBackground();
|
||||
@@ -1004,7 +985,7 @@ void Title::runDemoGame() {
|
||||
// Temporalmente ponemos section para que el constructor de Game funcione
|
||||
section->name = SECTION_PROG_GAME;
|
||||
section->subsection = SUBSECTION_GAME_PLAY_1P;
|
||||
demoGame = new Game(1, 0, renderer, screen, asset, lang, input, true, options, section);
|
||||
demoGame = new Game(1, 0, renderer, screen, asset, lang, input, true, section);
|
||||
demoGameActive = true;
|
||||
// Restauramos section para que Director no transicione fuera de Title
|
||||
section->name = SECTION_PROG_TITLE;
|
||||
@@ -1018,17 +999,17 @@ bool Title::updatePlayerInputs(int numPlayer) {
|
||||
deviceIndex[0] = 0;
|
||||
deviceIndex[1] = 0;
|
||||
|
||||
options->input[0].id = -1;
|
||||
options->input[0].name = "KEYBOARD";
|
||||
options->input[0].deviceType = INPUT_USE_KEYBOARD;
|
||||
Options::inputs[0].id = -1;
|
||||
Options::inputs[0].name = "KEYBOARD";
|
||||
Options::inputs[0].deviceType = INPUT_USE_KEYBOARD;
|
||||
|
||||
options->input[1].id = 0;
|
||||
options->input[1].name = "GAME CONTROLLER";
|
||||
options->input[1].deviceType = INPUT_USE_GAMECONTROLLER;
|
||||
Options::inputs[1].id = 0;
|
||||
Options::inputs[1].name = "GAME CONTROLLER";
|
||||
Options::inputs[1].deviceType = INPUT_USE_GAMECONTROLLER;
|
||||
|
||||
return true;
|
||||
} else { // Si hay mas de un dispositivo, se recorre el vector
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "numplayer:" << numPlayer << std::endl;
|
||||
std::cout << "deviceindex:" << deviceIndex[numPlayer] << std::endl;
|
||||
}
|
||||
@@ -1039,7 +1020,7 @@ bool Title::updatePlayerInputs(int numPlayer) {
|
||||
} else {
|
||||
deviceIndex[numPlayer] = 0;
|
||||
}
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "deviceindex:" << deviceIndex[numPlayer] << std::endl;
|
||||
}
|
||||
|
||||
@@ -1053,8 +1034,8 @@ bool Title::updatePlayerInputs(int numPlayer) {
|
||||
}
|
||||
|
||||
// Copia el dispositivo marcado por el indice a la variable de opciones de cada jugador
|
||||
options->input[0] = availableInputDevices[deviceIndex[0]];
|
||||
options->input[1] = availableInputDevices[deviceIndex[1]];
|
||||
Options::inputs[0] = availableInputDevices[deviceIndex[0]];
|
||||
Options::inputs[1] = availableInputDevices[deviceIndex[1]];
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1068,7 +1049,7 @@ void Title::createTiledBackground() {
|
||||
SDL_SetTextureScaleMode(background, Texture::currentScaleMode);
|
||||
}
|
||||
if (background == nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "TitleSurface could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1105,7 +1086,7 @@ void Title::createTiledBackground() {
|
||||
// El estado de Input lo mantiene al día Director via eventos SDL_EVENT_GAMEPAD_ADDED/REMOVED,
|
||||
// así que aquí solo leemos la lista actual sin reescanear.
|
||||
void Title::checkInputDevices() {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Filling devices for options menu..." << std::endl;
|
||||
}
|
||||
const int numControllers = input->getNumControllers();
|
||||
@@ -1119,7 +1100,7 @@ void Title::checkInputDevices() {
|
||||
temp.name = input->getControllerName(i);
|
||||
temp.deviceType = INPUT_USE_GAMECONTROLLER;
|
||||
availableInputDevices.push_back(temp);
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Device " << (int)availableInputDevices.size() << " - " << temp.name.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1129,7 +1110,7 @@ void Title::checkInputDevices() {
|
||||
temp.name = "KEYBOARD";
|
||||
temp.deviceType = INPUT_USE_KEYBOARD;
|
||||
availableInputDevices.push_back(temp);
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Device " << (int)availableInputDevices.size() << " - " << temp.name.c_str() << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "game/options.hpp" // for Options::Video, Options::Window (per snapshot cancel)
|
||||
#include "game/scenes/instructions.h" // for mode_e
|
||||
#include "utils/utils.h" // for input_t, options_t, section_t
|
||||
#include "utils/utils.h" // for input_t, section_t
|
||||
class AnimatedSprite;
|
||||
class Asset;
|
||||
class Fade;
|
||||
@@ -85,8 +86,11 @@ class Title {
|
||||
Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
|
||||
Uint8 postFade; // Opción a realizar cuando termina el fundido
|
||||
menu_t menu; // Variable con todos los objetos menus y sus variables
|
||||
struct options_t *options; // Variable con todas las variables de las opciones del programa
|
||||
options_t optionsPrevious; // Variable de respaldo para las opciones
|
||||
// Snapshot per a permetre CANCEL al menú d'opcions.
|
||||
Options::Video prevVideo;
|
||||
Options::Window prevWindow;
|
||||
Options::Settings prevSettings;
|
||||
std::vector<input_t> prevInputs;
|
||||
std::vector<input_t> availableInputDevices; // Vector con todos los metodos de control disponibles
|
||||
std::vector<int> deviceIndex; // Indice para el jugador [i] del vector de dispositivos de entrada disponibles
|
||||
|
||||
@@ -149,7 +153,7 @@ class Title {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Title(SDL_Renderer *renderer, Screen *screen, Input *input, Asset *asset, options_t *options, Lang *lang, section_t *section);
|
||||
Title(SDL_Renderer *renderer, Screen *screen, Input *input, Asset *asset, Lang *lang, section_t *section);
|
||||
|
||||
// Destructor
|
||||
~Title();
|
||||
|
||||
@@ -82,43 +82,6 @@ struct input_t {
|
||||
Uint8 deviceType; // Tipo de dispositivo (teclado o mando)
|
||||
};
|
||||
|
||||
// Estructura con opciones de la pantalla
|
||||
struct op_screen_t {
|
||||
int windowWidth; // Ancho de la ventana
|
||||
int windowHeight; // Alto de la ventana
|
||||
};
|
||||
|
||||
// Estructura con todas las opciones de configuración del programa
|
||||
struct options_t {
|
||||
Uint8 difficulty; // Dificultad del juego
|
||||
Uint8 playerSelected; // Jugador seleccionado para el modo 1P
|
||||
std::vector<input_t> input; // Modo de control (teclado o mando)
|
||||
Uint8 language; // Idioma usado en el juego
|
||||
|
||||
Uint32 videoMode; // Contiene el valor del modo de pantalla completa
|
||||
int windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana
|
||||
Uint32 filter; // Filtro usado para el escalado de la imagen
|
||||
bool vSync; // Indica si se quiere usar vsync o no
|
||||
int gameWidth; // Ancho de la resolucion nativa del juego
|
||||
int gameHeight; // Alto de la resolucion nativa del juego
|
||||
bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
|
||||
bool keepAspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
|
||||
bool borderEnabled; // Indica si ha de mostrar el borde en el modo de ventana
|
||||
int borderWidth; // Cantidad de pixels que se añade en el borde de la ventana
|
||||
int borderHeight; // Cantidad de pixels que se añade en el borde de la ventana
|
||||
palette_e palette; // Paleta de colores a usar en el juego
|
||||
bool console; // Indica si ha de mostrar información por la consola de texto
|
||||
|
||||
// GPU / shaders (persistent; also toggled via F9/F10/F11 hotkeys).
|
||||
// YAML migration pending — for now they live as flat keys in config.txt.
|
||||
bool videoGpuAcceleration = true; // Intenta usar SDL3 GPU si está disponible
|
||||
std::string videoGpuPreferredDriver; // Driver preferido para SDL3 GPU (vacío = auto)
|
||||
bool videoShaderEnabled = false; // Activa el post-procesado (PostFX / CrtPi)
|
||||
int videoShaderType = 0; // 0 = POSTFX, 1 = CRTPI
|
||||
|
||||
op_screen_t screen; // Opciones relativas a la clase screen
|
||||
};
|
||||
|
||||
// Calcula el cuadrado de la distancia entre dos puntos
|
||||
double distanceSquared(int x1, int y1, int x2, int y2);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user