593 lines
20 KiB
C++
593 lines
20 KiB
C++
#include "game/options.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <fstream> // Para ifstream, ofstream
|
|
#include <iostream> // Para cout, cerr
|
|
#include <string> // Para string
|
|
#include <unordered_map> // Para unordered_map
|
|
|
|
#include "core/input/input_types.hpp" // Para BUTTON_TO_STRING, STRING_TO_BUTTON
|
|
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
|
#include "game/defaults.hpp" // Para GameDefaults::VERSION
|
|
|
|
namespace Options {
|
|
|
|
// --- Funciones helper de conversión ---
|
|
|
|
// Mapa de nombres de filtro
|
|
const std::unordered_map<Screen::Filter, std::string> FILTER_TO_STRING = {
|
|
{Screen::Filter::NEAREST, "nearest"},
|
|
{Screen::Filter::LINEAR, "linear"}};
|
|
|
|
const std::unordered_map<std::string, Screen::Filter> STRING_TO_FILTER = {
|
|
{"nearest", Screen::Filter::NEAREST},
|
|
{"linear", Screen::Filter::LINEAR}};
|
|
|
|
// Mapa de scancodes comunes (los más usados para controles de juego)
|
|
const std::unordered_map<SDL_Scancode, std::string> SCANCODE_TO_STRING = {
|
|
// Flechas
|
|
{SDL_SCANCODE_LEFT, "LEFT"},
|
|
{SDL_SCANCODE_RIGHT, "RIGHT"},
|
|
{SDL_SCANCODE_UP, "UP"},
|
|
{SDL_SCANCODE_DOWN, "DOWN"},
|
|
// Letras
|
|
{SDL_SCANCODE_A, "A"},
|
|
{SDL_SCANCODE_B, "B"},
|
|
{SDL_SCANCODE_C, "C"},
|
|
{SDL_SCANCODE_D, "D"},
|
|
{SDL_SCANCODE_E, "E"},
|
|
{SDL_SCANCODE_F, "F"},
|
|
{SDL_SCANCODE_G, "G"},
|
|
{SDL_SCANCODE_H, "H"},
|
|
{SDL_SCANCODE_I, "I"},
|
|
{SDL_SCANCODE_J, "J"},
|
|
{SDL_SCANCODE_K, "K"},
|
|
{SDL_SCANCODE_L, "L"},
|
|
{SDL_SCANCODE_M, "M"},
|
|
{SDL_SCANCODE_N, "N"},
|
|
{SDL_SCANCODE_O, "O"},
|
|
{SDL_SCANCODE_P, "P"},
|
|
{SDL_SCANCODE_Q, "Q"},
|
|
{SDL_SCANCODE_R, "R"},
|
|
{SDL_SCANCODE_S, "S"},
|
|
{SDL_SCANCODE_T, "T"},
|
|
{SDL_SCANCODE_U, "U"},
|
|
{SDL_SCANCODE_V, "V"},
|
|
{SDL_SCANCODE_W, "W"},
|
|
{SDL_SCANCODE_X, "X"},
|
|
{SDL_SCANCODE_Y, "Y"},
|
|
{SDL_SCANCODE_Z, "Z"},
|
|
// Números
|
|
{SDL_SCANCODE_0, "0"},
|
|
{SDL_SCANCODE_1, "1"},
|
|
{SDL_SCANCODE_2, "2"},
|
|
{SDL_SCANCODE_3, "3"},
|
|
{SDL_SCANCODE_4, "4"},
|
|
{SDL_SCANCODE_5, "5"},
|
|
{SDL_SCANCODE_6, "6"},
|
|
{SDL_SCANCODE_7, "7"},
|
|
{SDL_SCANCODE_8, "8"},
|
|
{SDL_SCANCODE_9, "9"},
|
|
// Teclas especiales
|
|
{SDL_SCANCODE_SPACE, "SPACE"},
|
|
{SDL_SCANCODE_RETURN, "RETURN"},
|
|
{SDL_SCANCODE_ESCAPE, "ESCAPE"},
|
|
{SDL_SCANCODE_TAB, "TAB"},
|
|
{SDL_SCANCODE_BACKSPACE, "BACKSPACE"},
|
|
{SDL_SCANCODE_LSHIFT, "LSHIFT"},
|
|
{SDL_SCANCODE_RSHIFT, "RSHIFT"},
|
|
{SDL_SCANCODE_LCTRL, "LCTRL"},
|
|
{SDL_SCANCODE_RCTRL, "RCTRL"},
|
|
{SDL_SCANCODE_LALT, "LALT"},
|
|
{SDL_SCANCODE_RALT, "RALT"}};
|
|
|
|
const std::unordered_map<std::string, SDL_Scancode> STRING_TO_SCANCODE = {
|
|
// Flechas
|
|
{"LEFT", SDL_SCANCODE_LEFT},
|
|
{"RIGHT", SDL_SCANCODE_RIGHT},
|
|
{"UP", SDL_SCANCODE_UP},
|
|
{"DOWN", SDL_SCANCODE_DOWN},
|
|
// Letras
|
|
{"A", SDL_SCANCODE_A},
|
|
{"B", SDL_SCANCODE_B},
|
|
{"C", SDL_SCANCODE_C},
|
|
{"D", SDL_SCANCODE_D},
|
|
{"E", SDL_SCANCODE_E},
|
|
{"F", SDL_SCANCODE_F},
|
|
{"G", SDL_SCANCODE_G},
|
|
{"H", SDL_SCANCODE_H},
|
|
{"I", SDL_SCANCODE_I},
|
|
{"J", SDL_SCANCODE_J},
|
|
{"K", SDL_SCANCODE_K},
|
|
{"L", SDL_SCANCODE_L},
|
|
{"M", SDL_SCANCODE_M},
|
|
{"N", SDL_SCANCODE_N},
|
|
{"O", SDL_SCANCODE_O},
|
|
{"P", SDL_SCANCODE_P},
|
|
{"Q", SDL_SCANCODE_Q},
|
|
{"R", SDL_SCANCODE_R},
|
|
{"S", SDL_SCANCODE_S},
|
|
{"T", SDL_SCANCODE_T},
|
|
{"U", SDL_SCANCODE_U},
|
|
{"V", SDL_SCANCODE_V},
|
|
{"W", SDL_SCANCODE_W},
|
|
{"X", SDL_SCANCODE_X},
|
|
{"Y", SDL_SCANCODE_Y},
|
|
{"Z", SDL_SCANCODE_Z},
|
|
// Números
|
|
{"0", SDL_SCANCODE_0},
|
|
{"1", SDL_SCANCODE_1},
|
|
{"2", SDL_SCANCODE_2},
|
|
{"3", SDL_SCANCODE_3},
|
|
{"4", SDL_SCANCODE_4},
|
|
{"5", SDL_SCANCODE_5},
|
|
{"6", SDL_SCANCODE_6},
|
|
{"7", SDL_SCANCODE_7},
|
|
{"8", SDL_SCANCODE_8},
|
|
{"9", SDL_SCANCODE_9},
|
|
// Teclas especiales
|
|
{"SPACE", SDL_SCANCODE_SPACE},
|
|
{"RETURN", SDL_SCANCODE_RETURN},
|
|
{"ESCAPE", SDL_SCANCODE_ESCAPE},
|
|
{"TAB", SDL_SCANCODE_TAB},
|
|
{"BACKSPACE", SDL_SCANCODE_BACKSPACE},
|
|
{"LSHIFT", SDL_SCANCODE_LSHIFT},
|
|
{"RSHIFT", SDL_SCANCODE_RSHIFT},
|
|
{"LCTRL", SDL_SCANCODE_LCTRL},
|
|
{"RCTRL", SDL_SCANCODE_RCTRL},
|
|
{"LALT", SDL_SCANCODE_LALT},
|
|
{"RALT", SDL_SCANCODE_RALT}};
|
|
|
|
// Mapa extendido de botones de gamepad (incluye ejes como botones)
|
|
const std::unordered_map<int, std::string> GAMEPAD_BUTTON_TO_STRING = {
|
|
{SDL_GAMEPAD_BUTTON_WEST, "WEST"},
|
|
{SDL_GAMEPAD_BUTTON_NORTH, "NORTH"},
|
|
{SDL_GAMEPAD_BUTTON_EAST, "EAST"},
|
|
{SDL_GAMEPAD_BUTTON_SOUTH, "SOUTH"},
|
|
{SDL_GAMEPAD_BUTTON_START, "START"},
|
|
{SDL_GAMEPAD_BUTTON_BACK, "BACK"},
|
|
{SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, "LEFT_SHOULDER"},
|
|
{SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, "RIGHT_SHOULDER"},
|
|
{SDL_GAMEPAD_BUTTON_DPAD_UP, "DPAD_UP"},
|
|
{SDL_GAMEPAD_BUTTON_DPAD_DOWN, "DPAD_DOWN"},
|
|
{SDL_GAMEPAD_BUTTON_DPAD_LEFT, "DPAD_LEFT"},
|
|
{SDL_GAMEPAD_BUTTON_DPAD_RIGHT, "DPAD_RIGHT"},
|
|
{100, "L2_AS_BUTTON"},
|
|
{101, "R2_AS_BUTTON"},
|
|
{200, "LEFT_STICK_LEFT"},
|
|
{201, "LEFT_STICK_RIGHT"}};
|
|
|
|
const std::unordered_map<std::string, int> STRING_TO_GAMEPAD_BUTTON = {
|
|
{"WEST", SDL_GAMEPAD_BUTTON_WEST},
|
|
{"NORTH", SDL_GAMEPAD_BUTTON_NORTH},
|
|
{"EAST", SDL_GAMEPAD_BUTTON_EAST},
|
|
{"SOUTH", SDL_GAMEPAD_BUTTON_SOUTH},
|
|
{"START", SDL_GAMEPAD_BUTTON_START},
|
|
{"BACK", SDL_GAMEPAD_BUTTON_BACK},
|
|
{"LEFT_SHOULDER", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
|
|
{"RIGHT_SHOULDER", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
|
|
{"DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
|
|
{"DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
|
{"DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
|
{"DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
|
{"L2_AS_BUTTON", 100},
|
|
{"R2_AS_BUTTON", 101},
|
|
{"LEFT_STICK_LEFT", 200},
|
|
{"LEFT_STICK_RIGHT", 201}};
|
|
|
|
// Lista de paletas válidas
|
|
const std::vector<std::string> VALID_PALETTES = {
|
|
"black-and-white",
|
|
"green-phosphor",
|
|
"island-joy-16",
|
|
"lost-century",
|
|
"na16",
|
|
"orange-screen",
|
|
"pico-8",
|
|
"ruzx-spectrum",
|
|
"ruzx-spectrum-revision-2",
|
|
"steam-lords",
|
|
"sweetie-16",
|
|
"sweetie-16_bona",
|
|
"zx-spectrum",
|
|
"zx-spectrum-adjusted",
|
|
"zxarne-5-2"};
|
|
|
|
// Funciones helper de conversión
|
|
auto filterToString(Screen::Filter filter) -> std::string {
|
|
auto it = FILTER_TO_STRING.find(filter);
|
|
if (it != FILTER_TO_STRING.end()) {
|
|
return it->second;
|
|
}
|
|
return "nearest";
|
|
}
|
|
|
|
auto stringToFilter(const std::string& str) -> Screen::Filter {
|
|
auto it = STRING_TO_FILTER.find(str);
|
|
if (it != STRING_TO_FILTER.end()) {
|
|
return it->second;
|
|
}
|
|
return GameDefaults::VIDEO_FILTER;
|
|
}
|
|
|
|
auto scancodeToString(SDL_Scancode scancode) -> std::string {
|
|
auto it = SCANCODE_TO_STRING.find(scancode);
|
|
if (it != SCANCODE_TO_STRING.end()) {
|
|
return it->second;
|
|
}
|
|
// Fallback: devolver el código numérico como string
|
|
return std::to_string(static_cast<int>(scancode));
|
|
}
|
|
|
|
auto stringToScancode(const std::string& str, SDL_Scancode default_value) -> SDL_Scancode {
|
|
auto it = STRING_TO_SCANCODE.find(str);
|
|
if (it != STRING_TO_SCANCODE.end()) {
|
|
return it->second;
|
|
}
|
|
// Intentar parsear como número (compatibilidad hacia atrás)
|
|
try {
|
|
int val = std::stoi(str);
|
|
return static_cast<SDL_Scancode>(val);
|
|
} catch (...) {
|
|
return default_value;
|
|
}
|
|
}
|
|
|
|
auto gamepadButtonToString(int button) -> std::string {
|
|
auto it = GAMEPAD_BUTTON_TO_STRING.find(button);
|
|
if (it != GAMEPAD_BUTTON_TO_STRING.end()) {
|
|
return it->second;
|
|
}
|
|
// Fallback: devolver el código numérico como string
|
|
return std::to_string(button);
|
|
}
|
|
|
|
auto stringToGamepadButton(const std::string& str, int default_value) -> int {
|
|
auto it = STRING_TO_GAMEPAD_BUTTON.find(str);
|
|
if (it != STRING_TO_GAMEPAD_BUTTON.end()) {
|
|
return it->second;
|
|
}
|
|
// Intentar parsear como número (compatibilidad hacia atrás)
|
|
try {
|
|
return std::stoi(str);
|
|
} catch (...) {
|
|
return default_value;
|
|
}
|
|
}
|
|
|
|
auto isValidPalette(const std::string& palette) -> bool {
|
|
for (const auto& valid : VALID_PALETTES) {
|
|
if (valid == palette) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Crea e inicializa las opciones del programa
|
|
void init() {
|
|
#ifdef _DEBUG
|
|
console = true;
|
|
#else
|
|
console = false;
|
|
#endif
|
|
}
|
|
|
|
// Establece la ruta del fichero de configuración
|
|
void setConfigFile(const std::string& path) {
|
|
config_file_path = path;
|
|
}
|
|
|
|
// Carga las opciones desde el fichero configurado
|
|
auto loadFromFile() -> bool {
|
|
// Versión esperada del fichero
|
|
const std::string CONFIG_VERSION = GameDefaults::VERSION;
|
|
version = "";
|
|
|
|
// Intenta abrir y leer el fichero
|
|
std::ifstream file(config_file_path);
|
|
if (!file.good()) {
|
|
if (console) {
|
|
std::cout << "Config file not found, creating default: " << config_file_path << '\n';
|
|
}
|
|
saveToFile();
|
|
return true;
|
|
}
|
|
|
|
// Lee todo el contenido del fichero
|
|
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
|
file.close();
|
|
|
|
try {
|
|
if (console) {
|
|
std::cout << "Reading config file: " << config_file_path << '\n';
|
|
}
|
|
|
|
// Parsea el YAML
|
|
auto yaml = fkyaml::node::deserialize(content);
|
|
|
|
// Lee la versión
|
|
if (yaml.contains("version")) {
|
|
version = yaml["version"].get_value<std::string>();
|
|
}
|
|
|
|
// Si la versión no coincide, crea un fichero nuevo con valores por defecto
|
|
if (CONFIG_VERSION != version) {
|
|
if (console) {
|
|
std::cout << "Config version mismatch (expected: " << CONFIG_VERSION << ", got: " << version << "), creating new config\n";
|
|
}
|
|
init();
|
|
saveToFile();
|
|
return true;
|
|
}
|
|
|
|
// Lee window
|
|
if (yaml.contains("window")) {
|
|
const auto& win = yaml["window"];
|
|
if (win.contains("zoom")) {
|
|
try {
|
|
int val = win["zoom"].get_value<int>();
|
|
window.zoom = (val > 0) ? val : GameDefaults::WINDOW_ZOOM;
|
|
} catch (...) {
|
|
window.zoom = GameDefaults::WINDOW_ZOOM;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lee video
|
|
if (yaml.contains("video")) {
|
|
const auto& vid = yaml["video"];
|
|
|
|
// fullscreen (antes era "mode")
|
|
if (vid.contains("fullscreen")) {
|
|
try {
|
|
video.fullscreen = vid["fullscreen"].get_value<bool>();
|
|
} catch (...) {
|
|
video.fullscreen = GameDefaults::VIDEO_FULLSCREEN;
|
|
}
|
|
}
|
|
|
|
// filter (ahora es string)
|
|
if (vid.contains("filter")) {
|
|
try {
|
|
auto filter_str = vid["filter"].get_value<std::string>();
|
|
video.filter = stringToFilter(filter_str);
|
|
} catch (...) {
|
|
video.filter = GameDefaults::VIDEO_FILTER;
|
|
}
|
|
}
|
|
|
|
if (vid.contains("shaders")) {
|
|
try {
|
|
video.shaders = vid["shaders"].get_value<bool>();
|
|
} catch (...) {
|
|
video.shaders = GameDefaults::VIDEO_SHADERS;
|
|
}
|
|
}
|
|
|
|
if (vid.contains("vertical_sync")) {
|
|
try {
|
|
video.vertical_sync = vid["vertical_sync"].get_value<bool>();
|
|
} catch (...) {
|
|
video.vertical_sync = GameDefaults::VIDEO_VERTICAL_SYNC;
|
|
}
|
|
}
|
|
|
|
if (vid.contains("integer_scale")) {
|
|
try {
|
|
video.integer_scale = vid["integer_scale"].get_value<bool>();
|
|
} catch (...) {
|
|
video.integer_scale = GameDefaults::VIDEO_INTEGER_SCALE;
|
|
}
|
|
}
|
|
|
|
if (vid.contains("keep_aspect")) {
|
|
try {
|
|
video.keep_aspect = vid["keep_aspect"].get_value<bool>();
|
|
} catch (...) {
|
|
video.keep_aspect = GameDefaults::VIDEO_KEEP_ASPECT;
|
|
}
|
|
}
|
|
|
|
if (vid.contains("palette")) {
|
|
try {
|
|
auto palette_str = vid["palette"].get_value<std::string>();
|
|
if (isValidPalette(palette_str)) {
|
|
video.palette = palette_str;
|
|
} else {
|
|
video.palette = GameDefaults::PALETTE_NAME;
|
|
}
|
|
} catch (...) {
|
|
video.palette = GameDefaults::PALETTE_NAME;
|
|
}
|
|
}
|
|
|
|
// Lee border
|
|
if (vid.contains("border")) {
|
|
const auto& border = vid["border"];
|
|
|
|
if (border.contains("enabled")) {
|
|
try {
|
|
video.border.enabled = border["enabled"].get_value<bool>();
|
|
} catch (...) {
|
|
video.border.enabled = GameDefaults::BORDER_ENABLED;
|
|
}
|
|
}
|
|
|
|
if (border.contains("width")) {
|
|
try {
|
|
auto val = border["width"].get_value<float>();
|
|
video.border.width = (val > 0) ? val : GameDefaults::BORDER_WIDTH;
|
|
} catch (...) {
|
|
video.border.width = GameDefaults::BORDER_WIDTH;
|
|
}
|
|
}
|
|
|
|
if (border.contains("height")) {
|
|
try {
|
|
auto val = border["height"].get_value<float>();
|
|
video.border.height = (val > 0) ? val : GameDefaults::BORDER_HEIGHT;
|
|
} catch (...) {
|
|
video.border.height = GameDefaults::BORDER_HEIGHT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lee keyboard_controls (antes era "controls")
|
|
if (yaml.contains("keyboard_controls")) {
|
|
const auto& ctrl = yaml["keyboard_controls"];
|
|
|
|
if (ctrl.contains("key_left")) {
|
|
try {
|
|
auto key_str = ctrl["key_left"].get_value<std::string>();
|
|
keyboard_controls.key_left = stringToScancode(key_str, GameDefaults::CONTROL_KEY_LEFT);
|
|
} catch (...) {
|
|
keyboard_controls.key_left = GameDefaults::CONTROL_KEY_LEFT;
|
|
}
|
|
}
|
|
|
|
if (ctrl.contains("key_right")) {
|
|
try {
|
|
auto key_str = ctrl["key_right"].get_value<std::string>();
|
|
keyboard_controls.key_right = stringToScancode(key_str, GameDefaults::CONTROL_KEY_RIGHT);
|
|
} catch (...) {
|
|
keyboard_controls.key_right = GameDefaults::CONTROL_KEY_RIGHT;
|
|
}
|
|
}
|
|
|
|
if (ctrl.contains("key_jump")) {
|
|
try {
|
|
auto key_str = ctrl["key_jump"].get_value<std::string>();
|
|
keyboard_controls.key_jump = stringToScancode(key_str, GameDefaults::CONTROL_KEY_JUMP);
|
|
} catch (...) {
|
|
keyboard_controls.key_jump = GameDefaults::CONTROL_KEY_JUMP;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lee gamepad_controls
|
|
if (yaml.contains("gamepad_controls")) {
|
|
const auto& gp = yaml["gamepad_controls"];
|
|
|
|
if (gp.contains("button_left")) {
|
|
try {
|
|
auto button_str = gp["button_left"].get_value<std::string>();
|
|
gamepad_controls.button_left = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_LEFT);
|
|
} catch (...) {
|
|
gamepad_controls.button_left = GameDefaults::GAMEPAD_BUTTON_LEFT;
|
|
}
|
|
}
|
|
|
|
if (gp.contains("button_right")) {
|
|
try {
|
|
auto button_str = gp["button_right"].get_value<std::string>();
|
|
gamepad_controls.button_right = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_RIGHT);
|
|
} catch (...) {
|
|
gamepad_controls.button_right = GameDefaults::GAMEPAD_BUTTON_RIGHT;
|
|
}
|
|
}
|
|
|
|
if (gp.contains("button_jump")) {
|
|
try {
|
|
auto button_str = gp["button_jump"].get_value<std::string>();
|
|
gamepad_controls.button_jump = stringToGamepadButton(button_str, GameDefaults::GAMEPAD_BUTTON_JUMP);
|
|
} catch (...) {
|
|
gamepad_controls.button_jump = GameDefaults::GAMEPAD_BUTTON_JUMP;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (console) {
|
|
std::cout << "Config file loaded successfully\n\n";
|
|
}
|
|
|
|
return true;
|
|
|
|
} catch (const fkyaml::exception& e) {
|
|
if (console) {
|
|
std::cerr << "Error parsing YAML config: " << e.what() << '\n';
|
|
std::cerr << "Creating new config with defaults\n";
|
|
}
|
|
init();
|
|
saveToFile();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Guarda las opciones al fichero configurado
|
|
auto saveToFile() -> bool {
|
|
// Abre el fichero para escritura
|
|
std::ofstream file(config_file_path);
|
|
if (!file.is_open()) {
|
|
if (console) {
|
|
std::cerr << "Error: Unable to open file " << config_file_path << " for writing\n";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (console) {
|
|
std::cout << "Writing config file: " << config_file_path << '\n';
|
|
}
|
|
|
|
// Escribe el fichero manualmente para controlar el orden y los comentarios
|
|
file << "# JailDoctor's Dilemma - Configuration File\n";
|
|
file << "# \n";
|
|
file << "# This file is automatically generated and managed by the game.\n";
|
|
file << "# Manual edits are preserved if valid.\n";
|
|
file << "\n";
|
|
|
|
// VERSION
|
|
file << "# VERSION \n";
|
|
file << "version: \"" << GameDefaults::VERSION << "\"\n";
|
|
file << "\n";
|
|
|
|
// WINDOW
|
|
file << "# WINDOW\n";
|
|
file << "window:\n";
|
|
file << " zoom: " << window.zoom << "\n";
|
|
file << "\n";
|
|
|
|
// VIDEO
|
|
file << "# VIDEO \n";
|
|
file << "video:\n";
|
|
file << " fullscreen: " << (video.fullscreen ? "true" : "false") << "\n";
|
|
file << " filter: " << filterToString(video.filter) << " # filter: nearest (pixel perfect) | linear (smooth)\n";
|
|
file << " shaders: " << (video.shaders ? "true" : "false") << "\n";
|
|
file << " vertical_sync: " << (video.vertical_sync ? "true" : "false") << "\n";
|
|
file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n";
|
|
file << " keep_aspect: " << (video.keep_aspect ? "true" : "false") << "\n";
|
|
file << " palette: " << video.palette << "\n";
|
|
file << " border:\n";
|
|
file << " enabled: " << (video.border.enabled ? "true" : "false") << "\n";
|
|
file << " width: " << video.border.width << "\n";
|
|
file << " height: " << video.border.height << "\n";
|
|
file << "\n";
|
|
|
|
// KEYBOARD CONTROLS
|
|
file << "# KEYBOARD CONTROLS\n";
|
|
file << "keyboard_controls:\n";
|
|
file << " key_left: " << scancodeToString(keyboard_controls.key_left) << "\n";
|
|
file << " key_right: " << scancodeToString(keyboard_controls.key_right) << "\n";
|
|
file << " key_jump: " << scancodeToString(keyboard_controls.key_jump) << "\n";
|
|
file << "\n";
|
|
|
|
// GAMEPAD CONTROLS
|
|
file << "# GAMEPAD CONTROLS\n";
|
|
file << "gamepad_controls:\n";
|
|
file << " button_left: " << gamepadButtonToString(gamepad_controls.button_left) << "\n";
|
|
file << " button_right: " << gamepadButtonToString(gamepad_controls.button_right) << "\n";
|
|
file << " button_jump: " << gamepadButtonToString(gamepad_controls.button_jump) << "\n";
|
|
|
|
file.close();
|
|
|
|
if (console) {
|
|
std::cout << "Config file saved successfully\n\n";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace Options
|