afegida persistencia i fuck yamal
This commit is contained in:
@@ -35,6 +35,14 @@ All engine modules are flat C-style APIs (no classes), prefixed by subsystem:
|
||||
- **JF** (`source/core/jfile`) — File I/O: supports loading from filesystem folder or a packed resource file (`.jrf`). Currently uses folder mode (`data/`)
|
||||
- **shader** (`source/core/jshader`) — OpenGL post-processing shader (CRT effect) applied to the back buffer
|
||||
|
||||
### Configuration System (`source/game/`)
|
||||
|
||||
Follows the pattern from `jaildoctors_dilemma`:
|
||||
|
||||
- **defines.hpp** <20><> Game-wide constants (window title, version, screen dimensions)
|
||||
- **defaults.hpp** — Default values for all persistent options (audio, game)
|
||||
- **options.hpp/cpp** — `Options` namespace with structs, inline globals, and YAML load/save API. Config persists to `~/.config/jailgames/aee/config.yaml` (Linux), `%APPDATA%/jailgames/aee/` (Windows)
|
||||
|
||||
### Game Modules (`source/game/`)
|
||||
|
||||
- **ModuleSequence** — Non-gameplay screens: intro, menu, slides, banners, credits, death screen. State machine entry point (state=1)
|
||||
@@ -51,6 +59,7 @@ All engine modules are flat C-style APIs (no classes), prefixed by subsystem:
|
||||
|
||||
- `gif.h` — Header-only GIF decoder
|
||||
- `stb_vorbis.h` — stb single-header OGG decoder
|
||||
- `fkyaml_node.hpp` — Header-only YAML parser (fkYAML v0.4.2)
|
||||
|
||||
### Main Loop (`source/main.cpp`)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ set(APP_SOURCES
|
||||
source/core/jshader.cpp
|
||||
|
||||
# Game
|
||||
source/game/options.cpp
|
||||
source/game/bola.cpp
|
||||
source/game/engendro.cpp
|
||||
source/game/info.cpp
|
||||
|
||||
@@ -139,7 +139,8 @@ char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zer
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
// Crea la carpeta del sistema donde guardar datos.
|
||||
// Acepta rutas con subdirectorios (ej: "jailgames/aee") y crea toda la jerarquía.
|
||||
void file_setconfigfolder(const char *foldername)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -151,28 +152,15 @@ void file_setconfigfolder(const char *foldername)
|
||||
#elif __linux__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
config_folder = std::string(homedir) + "/." + foldername;
|
||||
config_folder = std::string(homedir) + "/.config/" + foldername;
|
||||
#endif
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat(config_folder.c_str(), &st) == -1)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int ret = mkdir(config_folder.c_str());
|
||||
#else
|
||||
int ret = mkdir(config_folder.c_str(), S_IRWXU);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
std::filesystem::create_directories(config_folder);
|
||||
}
|
||||
|
||||
const char *file_getconfigfolder() {
|
||||
std::string folder = config_folder + "/";
|
||||
static std::string folder;
|
||||
folder = config_folder + "/";
|
||||
return folder.c_str();
|
||||
}
|
||||
|
||||
|
||||
14726
source/external/fkyaml_node.hpp
vendored
Normal file
14726
source/external/fkyaml_node.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
source/game/defaults.hpp
Normal file
15
source/game/defaults.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace Defaults::Audio {
|
||||
constexpr float VOLUME = 1.0F;
|
||||
constexpr bool MUSIC_ENABLED = true;
|
||||
constexpr float MUSIC_VOLUME = 0.8F;
|
||||
constexpr bool SOUND_ENABLED = true;
|
||||
constexpr float SOUND_VOLUME = 1.0F;
|
||||
} // namespace Defaults::Audio
|
||||
|
||||
namespace Defaults::Game {
|
||||
constexpr int HABITACIO_INICIAL = 1;
|
||||
constexpr int PIRAMIDE_INICIAL = 255;
|
||||
constexpr int VIDES = 5;
|
||||
} // namespace Defaults::Game
|
||||
14
source/game/defines.hpp
Normal file
14
source/game/defines.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// Textos
|
||||
namespace Texts {
|
||||
constexpr const char* WINDOW_TITLE = "Aventures En Egipte";
|
||||
constexpr const char* VERSION = "1.00";
|
||||
} // namespace Texts
|
||||
|
||||
// Resolución del juego
|
||||
namespace Screen {
|
||||
constexpr int WIDTH = 320;
|
||||
constexpr int HEIGHT = 200;
|
||||
constexpr int BUFFER_SIZE = WIDTH * HEIGHT; // 64000
|
||||
} // namespace Screen
|
||||
146
source/game/options.cpp
Normal file
146
source/game/options.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include "game/options.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "game/defaults.hpp"
|
||||
#include "game/defines.hpp"
|
||||
|
||||
namespace Options {
|
||||
|
||||
// Estableix la ruta del fitxer de configuració
|
||||
void setConfigFile(const std::string& path) {
|
||||
config_file_path = path;
|
||||
}
|
||||
|
||||
// --- Funcions helper de càrrega ---
|
||||
|
||||
static void loadAudioConfigFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("audio")) return;
|
||||
const auto& node = yaml["audio"];
|
||||
|
||||
if (node.contains("volume"))
|
||||
audio.volume = node["volume"].get_value<float>();
|
||||
|
||||
if (node.contains("music")) {
|
||||
const auto& music = node["music"];
|
||||
if (music.contains("enabled"))
|
||||
audio.music_enabled = music["enabled"].get_value<bool>();
|
||||
if (music.contains("volume"))
|
||||
audio.music_volume = music["volume"].get_value<float>();
|
||||
}
|
||||
|
||||
if (node.contains("sound")) {
|
||||
const auto& sound = node["sound"];
|
||||
if (sound.contains("enabled"))
|
||||
audio.sound_enabled = sound["enabled"].get_value<bool>();
|
||||
if (sound.contains("volume"))
|
||||
audio.sound_volume = sound["volume"].get_value<float>();
|
||||
}
|
||||
}
|
||||
|
||||
static void loadGameConfigFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("game")) return;
|
||||
const auto& node = yaml["game"];
|
||||
|
||||
if (node.contains("habitacio_inicial"))
|
||||
game.habitacio_inicial = node["habitacio_inicial"].get_value<int>();
|
||||
if (node.contains("piramide_inicial"))
|
||||
game.piramide_inicial = node["piramide_inicial"].get_value<int>();
|
||||
if (node.contains("vides"))
|
||||
game.vides = node["vides"].get_value<int>();
|
||||
}
|
||||
|
||||
// Carrega les opcions des del fitxer configurat
|
||||
auto loadFromFile() -> bool {
|
||||
const std::string CONFIG_VERSION = Texts::VERSION;
|
||||
version = "";
|
||||
|
||||
std::ifstream file(config_file_path);
|
||||
if (!file.good()) {
|
||||
std::cout << "Config file not found, creating default: " << config_file_path << '\n';
|
||||
saveToFile();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
try {
|
||||
std::cout << "Reading config file: " << config_file_path << '\n';
|
||||
|
||||
auto yaml = fkyaml::node::deserialize(content);
|
||||
|
||||
if (yaml.contains("version")) {
|
||||
version = yaml["version"].get_value<std::string>();
|
||||
}
|
||||
|
||||
if (CONFIG_VERSION != version) {
|
||||
std::cout << "Config version mismatch (expected: " << CONFIG_VERSION
|
||||
<< ", got: " << version << "), creating new config\n";
|
||||
saveToFile();
|
||||
return true;
|
||||
}
|
||||
|
||||
loadAudioConfigFromYaml(yaml);
|
||||
loadGameConfigFromYaml(yaml);
|
||||
|
||||
std::cout << "Config file loaded successfully\n\n";
|
||||
return true;
|
||||
|
||||
} catch (const fkyaml::exception& e) {
|
||||
std::cerr << "Error parsing YAML config: " << e.what() << '\n';
|
||||
std::cerr << "Creating new config with defaults\n";
|
||||
saveToFile();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Guarda les opcions al fitxer configurat
|
||||
auto saveToFile() -> bool {
|
||||
std::ofstream file(config_file_path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error: Unable to open file " << config_file_path << " for writing\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Writing config file: " << config_file_path << '\n';
|
||||
|
||||
file << "# Aventures En Egipte - 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: \"" << Texts::VERSION << "\"\n";
|
||||
file << "\n";
|
||||
|
||||
// AUDIO
|
||||
file << "# AUDIO\n";
|
||||
file << "audio:\n";
|
||||
file << " volume: " << audio.volume << "\n";
|
||||
file << " music:\n";
|
||||
file << " enabled: " << (audio.music_enabled ? "true" : "false") << "\n";
|
||||
file << " volume: " << audio.music_volume << "\n";
|
||||
file << " sound:\n";
|
||||
file << " enabled: " << (audio.sound_enabled ? "true" : "false") << "\n";
|
||||
file << " volume: " << audio.sound_volume << "\n";
|
||||
file << "\n";
|
||||
|
||||
// GAME
|
||||
file << "# GAME\n";
|
||||
file << "game:\n";
|
||||
file << " habitacio_inicial: " << game.habitacio_inicial << "\n";
|
||||
file << " piramide_inicial: " << game.piramide_inicial << "\n";
|
||||
file << " vides: " << game.vides << "\n";
|
||||
|
||||
file.close();
|
||||
|
||||
std::cout << "Config file saved successfully\n\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Options
|
||||
37
source/game/options.hpp
Normal file
37
source/game/options.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "game/defaults.hpp"
|
||||
#include "game/defines.hpp"
|
||||
|
||||
namespace Options {
|
||||
|
||||
// Opcions d'àudio
|
||||
struct Audio {
|
||||
bool music_enabled{Defaults::Audio::MUSIC_ENABLED};
|
||||
float music_volume{Defaults::Audio::MUSIC_VOLUME};
|
||||
bool sound_enabled{Defaults::Audio::SOUND_ENABLED};
|
||||
float sound_volume{Defaults::Audio::SOUND_VOLUME};
|
||||
float volume{Defaults::Audio::VOLUME};
|
||||
};
|
||||
|
||||
// Opcions de joc
|
||||
struct Game {
|
||||
int habitacio_inicial{Defaults::Game::HABITACIO_INICIAL};
|
||||
int piramide_inicial{Defaults::Game::PIRAMIDE_INICIAL};
|
||||
int vides{Defaults::Game::VIDES};
|
||||
};
|
||||
|
||||
// --- Variables globals ---
|
||||
inline std::string version{};
|
||||
inline Audio audio{};
|
||||
inline Game game{};
|
||||
inline std::string config_file_path{};
|
||||
|
||||
// --- API ---
|
||||
void setConfigFile(const std::string& path);
|
||||
auto loadFromFile() -> bool;
|
||||
auto saveToFile() -> bool;
|
||||
|
||||
} // namespace Options
|
||||
@@ -2,46 +2,32 @@
|
||||
#include "core/jdraw8.hpp"
|
||||
#include "core/jail_audio.hpp"
|
||||
#include "core/jfile.hpp"
|
||||
#include "game/defines.hpp"
|
||||
#include "game/info.hpp"
|
||||
#include "game/modulegame.hpp"
|
||||
#include "game/modulesequence.hpp"
|
||||
#include "game/options.hpp"
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
#ifndef WIN32
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
*/
|
||||
|
||||
int main( int argc, char* args[] ) {
|
||||
|
||||
//file_setresourcefilename("data.jrf");
|
||||
/*#ifdef WIN32
|
||||
JF_SetResourceFile("data.jrf");
|
||||
#else
|
||||
char res_file[255] = "";
|
||||
strcpy(res_file, dirname(args[0]));
|
||||
#ifdef __APPLE__
|
||||
strcat(res_file, "/../Resources/data.jrf");
|
||||
#else
|
||||
strcat(res_file, "/data.jrf");
|
||||
#endif
|
||||
printf("ARXIU DE RECURSOS: %s\n", res_file);
|
||||
JF_SetResourceFile(res_file);
|
||||
#endif
|
||||
*/
|
||||
srand( unsigned(time(NULL)) );
|
||||
|
||||
// Crea la carpeta de configuració i carrega les opcions
|
||||
file_setconfigfolder("jailgames/aee");
|
||||
Options::setConfigFile(std::string(file_getconfigfolder()) + "config.yaml");
|
||||
Options::loadFromFile();
|
||||
|
||||
JG_Init();
|
||||
JD8_Init("Aventures En Egipte");
|
||||
JD8_Init(Texts::WINDOW_TITLE);
|
||||
JA_Init(48000, SDL_AUDIO_S16, 2);
|
||||
|
||||
info::num_habitacio = 1;
|
||||
info::num_piramide = 255;
|
||||
info::num_habitacio = Options::game.habitacio_inicial;
|
||||
info::num_piramide = Options::game.piramide_inicial;
|
||||
info::diners = 0;
|
||||
info::diamants = 0;
|
||||
info::vida = 5;
|
||||
info::vida = Options::game.vides;
|
||||
info::momies = 0;
|
||||
info::nou_personatge = false;
|
||||
info::pepe_activat = false;
|
||||
@@ -71,10 +57,11 @@ int main( int argc, char* args[] ) {
|
||||
}
|
||||
}
|
||||
|
||||
Options::saveToFile();
|
||||
|
||||
JA_Quit();
|
||||
JD8_Quit();
|
||||
JG_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user