forked from jaildesigner-jailgames/jaildoctors_dilemma
creada carpeta source2
This commit is contained in:
175
source2/Game/Gameplay/cheevos.cpp
Normal file
175
source2/Game/Gameplay/cheevos.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "cheevos.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stddef.h> // Para NULL
|
||||
|
||||
#include <fstream> // Para basic_ostream, operator<<, basic_ofstream
|
||||
#include <iostream> // Para cout, cerr
|
||||
|
||||
#include "options.h" // Para Options, options
|
||||
#include "ui/notifier.h" // Para Notifier
|
||||
|
||||
// [SINGLETON]
|
||||
Cheevos* Cheevos::cheevos_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
void Cheevos::init(const std::string& file) {
|
||||
Cheevos::cheevos_ = new Cheevos(file);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
void Cheevos::destroy() {
|
||||
delete Cheevos::cheevos_;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
Cheevos* Cheevos::get() {
|
||||
return Cheevos::cheevos_;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Cheevos::Cheevos(const std::string& file)
|
||||
: file_(file) {
|
||||
init();
|
||||
loadFromFile();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Cheevos::~Cheevos() {
|
||||
saveToFile();
|
||||
}
|
||||
|
||||
// Inicializa los logros
|
||||
void Cheevos::init() {
|
||||
cheevos_list_.clear();
|
||||
cheevos_list_.emplace_back(1, "SHINY THINGS", "Get 25% of the items", 2);
|
||||
cheevos_list_.emplace_back(2, "HALF THE WORK", "Get 50% of the items", 2);
|
||||
cheevos_list_.emplace_back(3, "GETTING THERE", "Get 75% of the items", 2);
|
||||
cheevos_list_.emplace_back(4, "THE COLLECTOR", "Get 100% of the items", 2);
|
||||
cheevos_list_.emplace_back(5, "WANDERING AROUND", "Visit 20 rooms", 2);
|
||||
cheevos_list_.emplace_back(6, "I GOT LOST", "Visit 40 rooms", 2);
|
||||
cheevos_list_.emplace_back(7, "I LIKE TO EXPLORE", "Visit all rooms", 2);
|
||||
cheevos_list_.emplace_back(8, "FINISH THE GAME", "Complete the game", 2);
|
||||
cheevos_list_.emplace_back(9, "I WAS SUCKED BY A HOLE", "Complete the game without entering the jail", 2);
|
||||
cheevos_list_.emplace_back(10, "MY LITTLE PROJECTS", "Complete the game with all items", 2);
|
||||
cheevos_list_.emplace_back(11, "I LIKE MY MULTICOLOURED FRIENDS", "Complete the game without dying", 2);
|
||||
cheevos_list_.emplace_back(12, "SHIT PROJECTS DONE FAST", "Complete the game in under 30 minutes", 2);
|
||||
}
|
||||
|
||||
// Busca un logro por id y devuelve el indice
|
||||
int Cheevos::find(int id) {
|
||||
for (int i = 0; i < (int)cheevos_list_.size(); ++i) {
|
||||
if (cheevos_list_[i].id == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Desbloquea un logro
|
||||
void Cheevos::unlock(int id) {
|
||||
const int INDEX = find(id);
|
||||
|
||||
// Si el índice es inválido, el logro no es válido, ya está completado o el sistema de logros no está habilitado, no hacemos nada
|
||||
if (INDEX == -1 || !cheevos_list_.at(INDEX).obtainable || cheevos_list_.at(INDEX).completed || !enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Marcar el logro como completado
|
||||
cheevos_list_.at(INDEX).completed = true;
|
||||
|
||||
// Mostrar notificación en la pantalla
|
||||
Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", cheevos_list_.at(INDEX).caption}, NotificationText::CENTER, CHEEVO_NOTIFICATION_DURATION /*, cheevos_list_.at(INDEX).icon*/);
|
||||
|
||||
// Guardar el estado de los logros
|
||||
saveToFile();
|
||||
}
|
||||
|
||||
// Invalida un logro
|
||||
void Cheevos::setUnobtainable(int id) {
|
||||
const int index = find(id);
|
||||
|
||||
// Si el índice es válido, se invalida el logro
|
||||
if (index != -1) {
|
||||
cheevos_list_.at(index).obtainable = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Carga el estado de los logros desde un fichero
|
||||
void Cheevos::loadFromFile() {
|
||||
std::ifstream file(file_, std::ios::binary);
|
||||
|
||||
// El fichero no existe
|
||||
if (!file) {
|
||||
if (options.console) {
|
||||
std::cout << "Warning: Unable to open " << file_ << "! Creating new file..." << std::endl;
|
||||
}
|
||||
|
||||
// Crea el fichero en modo escritura (binario)
|
||||
std::ofstream newFile(file_, std::ios::binary);
|
||||
|
||||
if (newFile) {
|
||||
if (options.console) {
|
||||
std::cout << "New " << file_ << " created!" << std::endl;
|
||||
}
|
||||
|
||||
// Guarda la información
|
||||
for (const auto& cheevo : cheevos_list_) {
|
||||
newFile.write(reinterpret_cast<const char*>(&cheevo.completed), sizeof(bool));
|
||||
}
|
||||
} else {
|
||||
if (options.console) {
|
||||
std::cerr << "Error: Unable to create " << file_ << "!" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
// El fichero existe
|
||||
else {
|
||||
if (options.console) {
|
||||
std::cout << "Reading " << file_ << std::endl;
|
||||
}
|
||||
|
||||
// Carga los datos
|
||||
for (auto& cheevo : cheevos_list_) {
|
||||
file.read(reinterpret_cast<char*>(&cheevo.completed), sizeof(bool));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Guarda el estado de los logros en un fichero
|
||||
void Cheevos::saveToFile() {
|
||||
// Abre el fichero en modo escritura (binario)
|
||||
SDL_IOStream* file = SDL_IOFromFile(this->file_.c_str(), "w+b");
|
||||
if (file != nullptr) {
|
||||
// Guarda la información
|
||||
for (int i = 0; i < (int)cheevos_list_.size(); ++i) {
|
||||
SDL_WriteIO(file, &cheevos_list_[i].completed, sizeof(bool));
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
SDL_CloseIO(file);
|
||||
} else {
|
||||
if (options.console) {
|
||||
std::cout << "Error: Unable to save file! " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve el número total de logros desbloqueados
|
||||
int Cheevos::getTotalUnlockedAchievements() {
|
||||
int count = 0;
|
||||
for (const auto& cheevo : cheevos_list_) {
|
||||
if (cheevo.completed) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Elimina el estado "no obtenible"
|
||||
void Cheevos::clearUnobtainableState() {
|
||||
for (auto& cheevo : cheevos_list_) {
|
||||
cheevo.obtainable = true;
|
||||
}
|
||||
}
|
||||
83
source2/Game/Gameplay/cheevos.h
Normal file
83
source2/Game/Gameplay/cheevos.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
// Struct para los logros
|
||||
struct Achievement
|
||||
{
|
||||
int id; // Identificador del logro
|
||||
std::string caption; // Texto con el nombre del logro
|
||||
std::string description; // Texto que describe el logro
|
||||
int icon; // Indice del icono a utilizar en la notificación
|
||||
bool completed; // Indica si se ha obtenido el logro
|
||||
bool obtainable; // Indica si se puede obtener el logro
|
||||
|
||||
// Constructor vacío
|
||||
Achievement() : id(0), icon(0), completed(false), obtainable(true) {}
|
||||
|
||||
// Constructor parametrizado
|
||||
Achievement(int id, const std::string &caption, const std::string &description, int icon, bool completed = false, bool obtainable = true)
|
||||
: id(id), caption(caption), description(description), icon(icon), completed(completed), obtainable(obtainable) {}
|
||||
};
|
||||
|
||||
class Cheevos
|
||||
{
|
||||
private:
|
||||
// [SINGLETON] Objeto privado
|
||||
static Cheevos *cheevos_;
|
||||
|
||||
// Variables
|
||||
std::vector<Achievement> cheevos_list_; // Listado de logros
|
||||
bool enabled_ = true; // Indica si los logros se pueden obtener
|
||||
std::string file_; // Fichero donde leer/almacenar el estado de los logros
|
||||
|
||||
// Inicializa los logros
|
||||
void init();
|
||||
|
||||
// Busca un logro por id y devuelve el índice
|
||||
int find(int id);
|
||||
|
||||
// Carga el estado de los logros desde un fichero
|
||||
void loadFromFile();
|
||||
|
||||
// Guarda el estado de los logros en un fichero
|
||||
void saveToFile();
|
||||
|
||||
// Constructor
|
||||
explicit Cheevos(const std::string &file);
|
||||
|
||||
// Destructor
|
||||
~Cheevos();
|
||||
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init(const std::string &file);
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static Cheevos *get();
|
||||
|
||||
// Desbloquea un logro
|
||||
void unlock(int id);
|
||||
|
||||
// Invalida un logro
|
||||
void setUnobtainable(int id);
|
||||
|
||||
// Elimina el estado "no obtenible"
|
||||
void clearUnobtainableState();
|
||||
|
||||
// Habilita o deshabilita los logros
|
||||
void enable(bool value) { enabled_ = value; }
|
||||
|
||||
// Lista los logros
|
||||
const std::vector<Achievement>& list() const { return cheevos_list_; }
|
||||
|
||||
// Devuelve el número total de logros desbloqueados
|
||||
int getTotalUnlockedAchievements();
|
||||
|
||||
// Devuelve el número total de logros
|
||||
int size() { return cheevos_list_.size(); }
|
||||
};
|
||||
75
source2/Game/Gameplay/item_tracker.cpp
Normal file
75
source2/Game/Gameplay/item_tracker.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "item_tracker.h"
|
||||
|
||||
// [SINGLETON]
|
||||
ItemTracker* ItemTracker::item_tracker_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
void ItemTracker::init() {
|
||||
ItemTracker::item_tracker_ = new ItemTracker();
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
void ItemTracker::destroy() {
|
||||
delete ItemTracker::item_tracker_;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
ItemTracker* ItemTracker::get() {
|
||||
return ItemTracker::item_tracker_;
|
||||
}
|
||||
|
||||
// Comprueba si el objeto ya ha sido cogido
|
||||
bool ItemTracker::hasBeenPicked(const std::string& name, SDL_FPoint pos) {
|
||||
// Primero busca si ya hay una entrada con ese nombre
|
||||
if (const int index = findByName(name); index != -1) {
|
||||
// Luego busca si existe ya una entrada con esa posición
|
||||
if (findByPos(index, pos) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Añade el objeto a la lista de objetos cogidos
|
||||
void ItemTracker::addItem(const std::string& name, SDL_FPoint pos) {
|
||||
// Comprueba si el objeto no ha sido recogido con anterioridad
|
||||
if (!hasBeenPicked(name, pos)) {
|
||||
// Primero busca si ya hay una entrada con ese nombre
|
||||
if (const int index = findByName(name); index != -1) {
|
||||
item_list_.at(index).pos.push_back(pos);
|
||||
}
|
||||
// En caso contrario crea la entrada
|
||||
else {
|
||||
item_list_.emplace_back(name, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Busca una entrada en la lista por nombre
|
||||
int ItemTracker::findByName(const std::string& name) {
|
||||
int i = 0;
|
||||
|
||||
for (const auto& l : item_list_) {
|
||||
if (l.name == name) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Busca una entrada en la lista por posición
|
||||
int ItemTracker::findByPos(int index, SDL_FPoint pos) {
|
||||
int i = 0;
|
||||
|
||||
for (const auto& l : item_list_[index].pos) {
|
||||
if ((l.x == pos.x) && (l.y == pos.y)) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
54
source2/Game/Gameplay/item_tracker.h
Normal file
54
source2/Game/Gameplay/item_tracker.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
|
||||
struct ItemTrackerData {
|
||||
std::string name; // Nombre de la habitación donde se encuentra el objeto
|
||||
std::vector<SDL_FPoint> pos; // Lista de objetos cogidos de la habitación
|
||||
|
||||
// Constructor
|
||||
ItemTrackerData(const std::string& name, const SDL_FPoint& position)
|
||||
: name(name) {
|
||||
pos.push_back(position);
|
||||
}
|
||||
};
|
||||
|
||||
class ItemTracker {
|
||||
private:
|
||||
// [SINGLETON] Objeto privado
|
||||
static ItemTracker* item_tracker_;
|
||||
|
||||
// Variables
|
||||
std::vector<ItemTrackerData> item_list_; // Lista con todos los objetos recogidos
|
||||
|
||||
// Busca una entrada en la lista por nombre
|
||||
int findByName(const std::string& name);
|
||||
|
||||
// Busca una entrada en la lista por posición
|
||||
int findByPos(int index, SDL_FPoint pos);
|
||||
|
||||
// Constructor
|
||||
ItemTracker() = default;
|
||||
|
||||
// Destructor
|
||||
~ItemTracker() = default;
|
||||
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init();
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static ItemTracker* get();
|
||||
|
||||
// Comprueba si el objeto ya ha sido cogido
|
||||
bool hasBeenPicked(const std::string& name, SDL_FPoint pos);
|
||||
|
||||
// Añade el objeto a la lista de objetos cogidos
|
||||
void addItem(const std::string& name, SDL_FPoint pos);
|
||||
};
|
||||
219
source2/Game/Gameplay/options.cpp
Normal file
219
source2/Game/Gameplay/options.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "options.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm> // Para find_if
|
||||
#include <cctype> // Para isspace
|
||||
#include <fstream> // Para basic_ostream, operator<<, basic_ofstream
|
||||
#include <functional> // Para function
|
||||
#include <iostream> // Para cout, cerr
|
||||
#include <sstream> // Para basic_istringstream
|
||||
#include <string> // Para char_traits, string, operator<<, hash
|
||||
#include <unordered_map> // Para unordered_map, operator==, _Node_const_i...
|
||||
#include <utility> // Para pair
|
||||
|
||||
// Variables
|
||||
Options options;
|
||||
|
||||
bool setOptions(const std::string& var, const std::string& value);
|
||||
|
||||
// Crea e inicializa las opciones del programa
|
||||
void initOptions() {
|
||||
options = Options();
|
||||
|
||||
#ifdef DEBUG
|
||||
options.section = SectionState(Section::ENDING2, Subsection::LOGO_TO_INTRO);
|
||||
options.console = true;
|
||||
#else
|
||||
options.section = SectionState(Section::LOGO, Subsection::LOGO_TO_INTRO);
|
||||
options.console = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Carga las opciones desde un fichero
|
||||
bool loadOptionsFromFile(const std::string& file_path) {
|
||||
// Indicador de éxito en la carga
|
||||
bool success = true;
|
||||
|
||||
// Versión actual del fichero
|
||||
const std::string configVersion = options.version;
|
||||
options.version = "";
|
||||
|
||||
// Variables para manejar el fichero
|
||||
std::ifstream file(file_path);
|
||||
|
||||
// Si el fichero se puede abrir
|
||||
if (file.good()) {
|
||||
// Procesa el fichero línea a línea
|
||||
if (options.console) {
|
||||
std::cout << "Reading file config.txt\n";
|
||||
}
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
// Elimina espacios en blanco iniciales y finales
|
||||
line = std::string(std::find_if(line.begin(), line.end(), [](int ch) { return !std::isspace(ch); }),
|
||||
line.end());
|
||||
line.erase(std::find_if(line.rbegin(), line.rend(), [](int ch) { return !std::isspace(ch); })
|
||||
.base(),
|
||||
line.end());
|
||||
|
||||
// Ignora líneas vacías o comentarios
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Usa un stringstream para dividir la línea en dos partes
|
||||
std::istringstream iss(line);
|
||||
std::string key, value;
|
||||
|
||||
if (iss >> key >> value) {
|
||||
if (!setOptions(key, value)) {
|
||||
if (options.console) {
|
||||
std::cout << "Warning: file config.txt\n";
|
||||
std::cout << "unknown parameter " << key << std::endl;
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
if (options.console) {
|
||||
std::cout << "Closing file config.txt\n\n";
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
// Crea el fichero con los valores por defecto
|
||||
saveOptionsToFile(file_path);
|
||||
}
|
||||
|
||||
// Si la versión de fichero no coincide, crea un fichero nuevo con los valores por defecto
|
||||
if (configVersion != options.version) {
|
||||
initOptions();
|
||||
saveOptionsToFile(file_path);
|
||||
if (options.console) {
|
||||
std::cout << "Wrong config file: initializing options.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Guarda las opciones en un fichero
|
||||
bool saveOptionsToFile(const std::string& file_path) {
|
||||
// Crea y abre el fichero de texto
|
||||
std::ofstream file(file_path);
|
||||
bool success = file.is_open(); // Verifica si el archivo se abrió correctamente
|
||||
|
||||
if (!success) // Si no se pudo abrir el archivo, muestra un mensaje de error y devuelve false
|
||||
{
|
||||
if (options.console) {
|
||||
std::cerr << "Error: Unable to open file " << file_path << " for writing." << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.console) {
|
||||
std::cout << file_path << " open for writing" << std::endl;
|
||||
}
|
||||
|
||||
// Escribe en el fichero
|
||||
file << "# Versión de la configuración\n";
|
||||
file << "version " << options.version << "\n";
|
||||
|
||||
file << "\n## CONTROL\n";
|
||||
file << "# Esquema de control: 0 = Cursores, 1 = OPQ, 2 = WAD\n";
|
||||
file << "keys " << static_cast<int>(options.keys) << "\n";
|
||||
|
||||
file << "\n## WINDOW\n";
|
||||
file << "# Zoom de la ventana: 1 = Normal, 2 = Doble, 3 = Triple, ...\n";
|
||||
file << "window.zoom " << options.window.zoom << "\n";
|
||||
|
||||
file << "\n## VIDEO\n";
|
||||
file << "# Modo de video: 0 = Ventana, 1 = Pantalla completa, 2 = Pantalla completa (escritorio)\n";
|
||||
file << "video.mode " << options.video.fullscreen << "\n\n";
|
||||
file << "# Filtro de pantalla: 0 = Nearest, 1 = Linear\n";
|
||||
file << "video.filter " << static_cast<int>(options.video.filter) << "\n\n";
|
||||
file << "# Shaders: 1 = Activado, 0 = Desactivado\n";
|
||||
file << "video.shaders " << boolToString(options.video.shaders) << "\n\n";
|
||||
file << "# Sincronización vertical: 1 = Activado, 0 = Desactivado\n";
|
||||
file << "video.vertical_sync " << boolToString(options.video.vertical_sync) << "\n\n";
|
||||
file << "# Escalado entero: 1 = Activado, 0 = Desactivado\n";
|
||||
file << "video.integer_scale " << boolToString(options.video.integer_scale) << "\n\n";
|
||||
file << "# Mantener aspecto: 1 = Activado, 0 = Desactivado\n";
|
||||
file << "video.keep_aspect " << boolToString(options.video.keep_aspect) << "\n\n";
|
||||
file << "# Borde: 1 = Activado, 0 = Desactivado\n";
|
||||
file << "video.border.enabled " << boolToString(options.video.border.enabled) << "\n\n";
|
||||
file << "# Ancho del borde\n";
|
||||
file << "video.border.width " << options.video.border.width << "\n\n";
|
||||
file << "# Alto del borde\n";
|
||||
file << "video.border.height " << options.video.border.height << "\n\n";
|
||||
file << "# Paleta\n";
|
||||
file << "video.palette " << options.video.palette << "\n";
|
||||
|
||||
// Cierra el fichero
|
||||
file.close();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool setOptions(const std::string& var, const std::string& value) {
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> optionHandlers = {
|
||||
{"version", [](const std::string& v) { options.version = v; }},
|
||||
{"keys", [](const std::string& v) {
|
||||
int val = safeStoi(v, static_cast<int>(DEFAULT_CONTROL_SCHEME));
|
||||
if (val == static_cast<int>(ControlScheme::CURSOR) || val == static_cast<int>(ControlScheme::OPQA) || val == static_cast<int>(ControlScheme::WASD)) {
|
||||
options.keys = static_cast<ControlScheme>(val);
|
||||
} else {
|
||||
options.keys = DEFAULT_CONTROL_SCHEME;
|
||||
}
|
||||
}},
|
||||
{"window.zoom", [](const std::string& v) {
|
||||
int val = safeStoi(v, DEFAULT_WINDOW_ZOOM);
|
||||
if (val > 0) {
|
||||
options.window.zoom = val;
|
||||
} else {
|
||||
options.window.zoom = DEFAULT_WINDOW_ZOOM;
|
||||
}
|
||||
}},
|
||||
{"video.mode", [](const std::string& v) { options.video.fullscreen = stringToBool(v); }},
|
||||
{"video.filter", [](const std::string& v) {
|
||||
int val = safeStoi(v, static_cast<int>(DEFAULT_VIDEO_FILTER));
|
||||
if (val == static_cast<int>(ScreenFilter::NEAREST) || val == static_cast<int>(ScreenFilter::LINEAR)) {
|
||||
options.video.filter = static_cast<ScreenFilter>(val);
|
||||
} else {
|
||||
options.video.filter = DEFAULT_VIDEO_FILTER;
|
||||
}
|
||||
}},
|
||||
{"video.shaders", [](const std::string& v) { options.video.shaders = stringToBool(v); }},
|
||||
{"video.vertical_sync", [](const std::string& v) { options.video.vertical_sync = stringToBool(v); }},
|
||||
{"video.integer_scale", [](const std::string& v) { options.video.integer_scale = stringToBool(v); }},
|
||||
{"video.keep_aspect", [](const std::string& v) { options.video.keep_aspect = stringToBool(v); }},
|
||||
{"video.border.enabled", [](const std::string& v) { options.video.border.enabled = stringToBool(v); }},
|
||||
{"video.border.width", [](const std::string& v) {
|
||||
int val = safeStoi(v, DEFAULT_BORDER_WIDTH);
|
||||
if (val > 0) {
|
||||
options.video.border.width = val;
|
||||
} else {
|
||||
options.video.border.width = DEFAULT_BORDER_WIDTH;
|
||||
}
|
||||
}},
|
||||
{"video.border.height", [](const std::string& v) {
|
||||
int val = safeStoi(v, DEFAULT_BORDER_HEIGHT);
|
||||
if (val > 0) {
|
||||
options.video.border.height = val;
|
||||
} else {
|
||||
options.video.border.height = DEFAULT_BORDER_HEIGHT;
|
||||
}
|
||||
}},
|
||||
{"video.palette", [](const std::string& v) {
|
||||
options.video.palette = v;
|
||||
}}};
|
||||
|
||||
auto it = optionHandlers.find(var);
|
||||
if (it != optionHandlers.end()) {
|
||||
it->second(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
424
source2/Game/Gameplay/options.h
Normal file
424
source2/Game/Gameplay/options.h
Normal file
@@ -0,0 +1,424 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string> // Para string, basic_string
|
||||
|
||||
#include "screen.h" // Para ScreenFilter
|
||||
#include "utils.h" // Para Color, Palette
|
||||
|
||||
// Secciones del programa
|
||||
enum class Section {
|
||||
LOGO,
|
||||
LOADING_SCREEN,
|
||||
TITLE,
|
||||
CREDITS,
|
||||
GAME,
|
||||
DEMO,
|
||||
GAME_OVER,
|
||||
ENDING,
|
||||
ENDING2,
|
||||
QUIT
|
||||
};
|
||||
|
||||
// Subsecciones
|
||||
enum class Subsection {
|
||||
NONE,
|
||||
LOGO_TO_INTRO,
|
||||
LOGO_TO_TITLE,
|
||||
TITLE_WITH_LOADING_SCREEN,
|
||||
TITLE_WITHOUT_LOADING_SCREEN
|
||||
};
|
||||
|
||||
// Posiciones de las notificaciones
|
||||
enum class NotificationPosition {
|
||||
UPPER_LEFT,
|
||||
UPPER_CENTER,
|
||||
UPPER_RIGHT,
|
||||
BOTTOM_LEFT,
|
||||
BOTTOM_CENTER,
|
||||
BOTTOM_RIGHT,
|
||||
TOP,
|
||||
BOTTOM,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
CENTER,
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
// Tipos de control de teclado
|
||||
enum class ControlScheme {
|
||||
CURSOR,
|
||||
OPQA,
|
||||
WASD
|
||||
};
|
||||
|
||||
// Constantes
|
||||
constexpr int DEFAULT_GAME_WIDTH = 256; // Ancho de la ventana por defecto
|
||||
constexpr int DEFAULT_GAME_HEIGHT = 192; // Alto de la ventana por defecto
|
||||
constexpr int DEFAULT_WINDOW_ZOOM = 2; // Zoom de la ventana por defecto
|
||||
constexpr bool DEFAULT_VIDEO_MODE = false; // Modo de pantalla completa por defecto
|
||||
constexpr ScreenFilter DEFAULT_VIDEO_FILTER = ScreenFilter::NEAREST; // Filtro por defecto
|
||||
constexpr bool DEFAULT_VIDEO_VERTICAL_SYNC = true; // Vsync activado por defecto
|
||||
constexpr bool DEFAULT_VIDEO_SHADERS = false; // Shaders desactivados por defecto
|
||||
constexpr bool DEFAULT_VIDEO_INTEGER_SCALE = true; // Escalado entero activado por defecto
|
||||
constexpr bool DEFAULT_VIDEO_KEEP_ASPECT = true; // Mantener aspecto activado por defecto
|
||||
constexpr bool DEFAULT_BORDER_ENABLED = true; // Borde activado por defecto
|
||||
constexpr int DEFAULT_BORDER_WIDTH = 32; // Ancho del borde por defecto
|
||||
constexpr int DEFAULT_BORDER_HEIGHT = 24; // Alto del borde por defecto
|
||||
constexpr int DEFAULT_SOUND_VOLUME = 100; // Volumen por defecto de los efectos de sonido
|
||||
constexpr bool DEFAULT_SOUND_ENABLED = true; // Sonido habilitado por defecto
|
||||
constexpr int DEFAULT_MUSIC_VOLUME = 80; // Volumen por defecto de la musica
|
||||
constexpr bool DEFAULT_MUSIC_ENABLED = true; // Musica habilitada por defecto
|
||||
constexpr int DEFAULT_AUDIO_VOLUME = 100; // Volumen por defecto
|
||||
constexpr bool DEFAULT_AUDIO_ENABLED = true; // Audio por defecto
|
||||
constexpr const char* DEFAULT_PALETTE = "zx-spectrum"; // Paleta por defecto
|
||||
constexpr Section DEFAULT_SECTION = Section::LOGO; // Sección por defecto
|
||||
constexpr Subsection DEFAULT_SUBSECTION = Subsection::LOGO_TO_INTRO; // Subsección por defecto
|
||||
constexpr ControlScheme DEFAULT_CONTROL_SCHEME = ControlScheme::CURSOR; // Control por defecto
|
||||
constexpr NotificationPosition DEFAULT_NOTIFICATION_POSITION = NotificationPosition::UPPER_LEFT; // Posición de las notificaciones por defecto
|
||||
constexpr bool DEFAULT_NOTIFICATION_SOUND = true; // Sonido de las notificaciones por defecto
|
||||
const Uint8 DEFAULT_NOTIFICATION_COLOR = static_cast<Uint8>(PaletteColor::BLUE); // Color de las notificaciones por defecto
|
||||
constexpr bool DEFAULT_CONSOLE = false; // Consola desactivada por defecto
|
||||
constexpr const char* DEFAULT_VERSION = "1.10"; // Versión por defecto
|
||||
|
||||
// Estructura para las opciones de las notificaciones
|
||||
struct OptionsNotification {
|
||||
NotificationPosition pos; // Ubicación de las notificaciones en pantalla
|
||||
bool sound; // Indica si las notificaciones suenan
|
||||
Uint8 color; // Color de las notificaciones
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsNotification()
|
||||
: pos(DEFAULT_NOTIFICATION_POSITION),
|
||||
sound(DEFAULT_NOTIFICATION_SOUND),
|
||||
color(DEFAULT_NOTIFICATION_COLOR) {}
|
||||
|
||||
// Constructor
|
||||
OptionsNotification(NotificationPosition p, bool s, Uint8 c)
|
||||
: pos(p),
|
||||
sound(s),
|
||||
color(c) {}
|
||||
|
||||
// Método que devuelve la posición horizontal
|
||||
NotificationPosition getHorizontalPosition() const {
|
||||
switch (pos) {
|
||||
case NotificationPosition::UPPER_LEFT:
|
||||
case NotificationPosition::BOTTOM_LEFT:
|
||||
return NotificationPosition::LEFT;
|
||||
case NotificationPosition::UPPER_CENTER:
|
||||
case NotificationPosition::BOTTOM_CENTER:
|
||||
return NotificationPosition::CENTER;
|
||||
case NotificationPosition::UPPER_RIGHT:
|
||||
case NotificationPosition::BOTTOM_RIGHT:
|
||||
return NotificationPosition::RIGHT;
|
||||
default:
|
||||
return NotificationPosition::UNKNOWN;
|
||||
}
|
||||
return NotificationPosition::UNKNOWN;
|
||||
}
|
||||
|
||||
// Método que devuelve la posición vertical
|
||||
NotificationPosition getVerticalPosition() const {
|
||||
switch (pos) {
|
||||
case NotificationPosition::UPPER_LEFT:
|
||||
case NotificationPosition::UPPER_CENTER:
|
||||
case NotificationPosition::UPPER_RIGHT:
|
||||
return NotificationPosition::TOP;
|
||||
case NotificationPosition::BOTTOM_LEFT:
|
||||
case NotificationPosition::BOTTOM_CENTER:
|
||||
case NotificationPosition::BOTTOM_RIGHT:
|
||||
return NotificationPosition::BOTTOM;
|
||||
default:
|
||||
return NotificationPosition::UNKNOWN;
|
||||
}
|
||||
return NotificationPosition::UNKNOWN;
|
||||
}
|
||||
};
|
||||
|
||||
// Estructura para saber la seccion y subseccion del programa
|
||||
struct SectionState {
|
||||
Section section;
|
||||
Subsection subsection;
|
||||
|
||||
// Constructor por defecto
|
||||
SectionState()
|
||||
: section(DEFAULT_SECTION),
|
||||
subsection(DEFAULT_SUBSECTION) {}
|
||||
|
||||
// Constructor
|
||||
SectionState(Section s, Subsection ss)
|
||||
: section(s),
|
||||
subsection(ss) {}
|
||||
};
|
||||
|
||||
// Estructura para albergar trucos
|
||||
struct Cheat {
|
||||
enum class CheatState : bool {
|
||||
DISABLED = false,
|
||||
ENABLED = true
|
||||
};
|
||||
|
||||
CheatState infinite_lives; // Indica si el jugador dispone de vidas infinitas
|
||||
CheatState invincible; // Indica si el jugador puede morir
|
||||
CheatState jail_is_open; // Indica si la Jail está abierta
|
||||
CheatState alternate_skin; // Indica si se usa una skin diferente para el jugador
|
||||
|
||||
// Constructor por defecto
|
||||
Cheat()
|
||||
: infinite_lives(CheatState::DISABLED),
|
||||
invincible(CheatState::DISABLED),
|
||||
jail_is_open(CheatState::DISABLED),
|
||||
alternate_skin(CheatState::DISABLED) {}
|
||||
|
||||
// Constructor
|
||||
Cheat(CheatState il, CheatState i, CheatState je, CheatState as)
|
||||
: infinite_lives(il),
|
||||
invincible(i),
|
||||
jail_is_open(je),
|
||||
alternate_skin(as) {}
|
||||
|
||||
// Método para comprobar si alguno de los tres primeros trucos está activo
|
||||
bool enabled() const {
|
||||
return infinite_lives == CheatState::ENABLED ||
|
||||
invincible == CheatState::ENABLED ||
|
||||
jail_is_open == CheatState::ENABLED;
|
||||
}
|
||||
};
|
||||
|
||||
// Estructura para almacenar estadísticas
|
||||
struct OptionsStats {
|
||||
int rooms; // Cantidad de habitaciones visitadas
|
||||
int items; // Cantidad de items obtenidos
|
||||
std::string worst_nightmare; // Habitación con más muertes acumuladas
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsStats()
|
||||
: rooms(0),
|
||||
items(0),
|
||||
worst_nightmare("") {}
|
||||
|
||||
// Constructor
|
||||
OptionsStats(int r, int i, const std::string& wn)
|
||||
: rooms(r),
|
||||
items(i),
|
||||
worst_nightmare(wn) {}
|
||||
};
|
||||
|
||||
// Estructura con opciones de la ventana
|
||||
struct OptionsWindow {
|
||||
std::string caption = "JailDoctor's Dilemma"; // Texto que aparece en la barra de título de la ventana
|
||||
int zoom; // Zoom de la ventana
|
||||
int max_zoom; // Máximo tamaño de zoom para la ventana
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsWindow()
|
||||
: zoom(DEFAULT_WINDOW_ZOOM),
|
||||
max_zoom(DEFAULT_WINDOW_ZOOM) {}
|
||||
|
||||
// Constructor
|
||||
OptionsWindow(int z, int mz)
|
||||
: zoom(z),
|
||||
max_zoom(mz) {}
|
||||
};
|
||||
|
||||
// Estructura para gestionar el borde de la pantalla
|
||||
struct Border {
|
||||
bool enabled; // Indica si se ha de mostrar el borde
|
||||
float width; // Ancho del borde
|
||||
float height; // Alto del borde
|
||||
|
||||
// Constructor por defecto
|
||||
Border()
|
||||
: enabled(DEFAULT_BORDER_ENABLED),
|
||||
width(DEFAULT_BORDER_WIDTH),
|
||||
height(DEFAULT_BORDER_HEIGHT) {}
|
||||
|
||||
// Constructor
|
||||
Border(bool e, float w, float h)
|
||||
: enabled(e),
|
||||
width(w),
|
||||
height(h) {}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de video
|
||||
struct OptionsVideo {
|
||||
bool fullscreen; // Contiene el valor del modo de pantalla completa
|
||||
ScreenFilter filter; // Filtro usado para el escalado de la imagen
|
||||
bool vertical_sync; // Indica si se quiere usar vsync o no
|
||||
bool shaders; // Indica si se van a usar shaders o no
|
||||
bool integer_scale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
|
||||
bool keep_aspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
|
||||
Border border; // Borde de la pantalla
|
||||
std::string palette; // Paleta de colores a usar en el juego
|
||||
std::string info; // Información sobre el modo de vídeo
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsVideo()
|
||||
: fullscreen(DEFAULT_VIDEO_MODE),
|
||||
filter(DEFAULT_VIDEO_FILTER),
|
||||
vertical_sync(DEFAULT_VIDEO_VERTICAL_SYNC),
|
||||
shaders(DEFAULT_VIDEO_SHADERS),
|
||||
integer_scale(DEFAULT_VIDEO_INTEGER_SCALE),
|
||||
keep_aspect(DEFAULT_VIDEO_KEEP_ASPECT),
|
||||
border(Border()),
|
||||
palette(DEFAULT_PALETTE) {}
|
||||
|
||||
// Constructor
|
||||
OptionsVideo(Uint32 m, ScreenFilter f, bool vs, bool s, bool is, bool ka, Border b, const std::string& p)
|
||||
: fullscreen(m),
|
||||
filter(f),
|
||||
vertical_sync(vs),
|
||||
shaders(s),
|
||||
integer_scale(is),
|
||||
keep_aspect(ka),
|
||||
border(b),
|
||||
palette(p) {}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de musica
|
||||
struct OptionsMusic {
|
||||
bool enabled; // Indica si la música suena o no
|
||||
int volume; // Volumen al que suena la música (0 a 128 internamente)
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsMusic()
|
||||
: enabled(DEFAULT_MUSIC_ENABLED),
|
||||
volume(convertVolume(DEFAULT_MUSIC_VOLUME)) {} // Usa el método estático para la conversión
|
||||
|
||||
// Constructor con parámetros
|
||||
OptionsMusic(bool e, int v)
|
||||
: enabled(e),
|
||||
volume(convertVolume(v)) {} // Convierte el volumen usando el método estático
|
||||
|
||||
// Método para establecer el volumen
|
||||
void setVolume(int v) {
|
||||
v = std::clamp(v, 0, 100); // Ajusta v al rango [0, 100]
|
||||
volume = convertVolume(v); // Convierte al rango interno
|
||||
}
|
||||
|
||||
// Método estático para convertir de 0-100 a 0-128
|
||||
static int convertVolume(int v) {
|
||||
return (v * 128) / 100;
|
||||
}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de sonido
|
||||
struct OptionsSound {
|
||||
bool enabled; // Indica si los sonidos suenan o no
|
||||
int volume; // Volumen al que suenan los sonidos (0 a 128 internamente)
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsSound()
|
||||
: enabled(DEFAULT_SOUND_ENABLED),
|
||||
volume(convertVolume(DEFAULT_SOUND_VOLUME)) {} // Usa el método estático para la conversión
|
||||
|
||||
// Constructor con parámetros
|
||||
OptionsSound(bool e, int v)
|
||||
: enabled(e),
|
||||
volume(convertVolume(v)) {} // También lo integra aquí
|
||||
|
||||
// Método para establecer el volumen
|
||||
void setVolume(int v) {
|
||||
v = std::clamp(v, 0, 100); // Ajusta v al rango [0, 100]
|
||||
volume = convertVolume(v); // Convierte al rango interno
|
||||
}
|
||||
|
||||
// Método estático para convertir de 0-100 a 0-128
|
||||
static int convertVolume(int v) {
|
||||
return (v * 128) / 100;
|
||||
}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de audio
|
||||
struct OptionsAudio {
|
||||
OptionsMusic music; // Opciones para la música
|
||||
OptionsSound sound; // Opciones para los efectos de sonido
|
||||
bool enabled; // Indica si el audio está activo o no
|
||||
int volume; // Volumen al que suenan el audio
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsAudio()
|
||||
: music(OptionsMusic()),
|
||||
sound(OptionsSound()),
|
||||
enabled(DEFAULT_AUDIO_ENABLED),
|
||||
volume(DEFAULT_AUDIO_VOLUME) {}
|
||||
|
||||
// Constructor
|
||||
OptionsAudio(OptionsMusic m, OptionsSound s, bool e, int v)
|
||||
: music(m),
|
||||
sound(s),
|
||||
enabled(e),
|
||||
volume(v) {}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de juego
|
||||
struct OptionsGame {
|
||||
float width; // Ancho de la resolucion del juego
|
||||
float height; // Alto de la resolucion del juego
|
||||
|
||||
// Constructor por defecto
|
||||
OptionsGame()
|
||||
: width(DEFAULT_GAME_WIDTH),
|
||||
height(DEFAULT_GAME_HEIGHT) {}
|
||||
|
||||
// Constructor
|
||||
OptionsGame(float w, float h)
|
||||
: width(w),
|
||||
height(h) {}
|
||||
};
|
||||
|
||||
// Estructura con todas las opciones de configuración del programa
|
||||
struct Options {
|
||||
std::string version; // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles
|
||||
bool console; // Indica si ha de mostrar información por la consola de texto
|
||||
Cheat cheats; // Contiene trucos y ventajas para el juego
|
||||
OptionsGame game; // Opciones de juego
|
||||
OptionsVideo video; // Opciones de video
|
||||
OptionsStats stats; // Datos con las estadisticas de juego
|
||||
OptionsNotification notifications; // Opciones relativas a las notificaciones;
|
||||
OptionsWindow window; // Opciones relativas a la ventana
|
||||
OptionsAudio audio; // Opciones relativas al audio
|
||||
ControlScheme keys; // Teclas usadas para jugar
|
||||
SectionState section; // Sección actual del programa
|
||||
|
||||
// Constructor por defecto
|
||||
Options()
|
||||
: version(DEFAULT_VERSION),
|
||||
console(DEFAULT_CONSOLE),
|
||||
cheats(Cheat()),
|
||||
game(OptionsGame()),
|
||||
video(OptionsVideo()),
|
||||
stats(OptionsStats()),
|
||||
notifications(OptionsNotification()),
|
||||
window(OptionsWindow()),
|
||||
audio(OptionsAudio()),
|
||||
keys(DEFAULT_CONTROL_SCHEME),
|
||||
section(SectionState()) {}
|
||||
|
||||
// Constructor
|
||||
Options(std::string cv, bool c, Cheat ch, OptionsGame g, OptionsVideo v, OptionsStats s, OptionsNotification n, OptionsWindow sw, OptionsAudio a, ControlScheme k, SectionState sec)
|
||||
: version(cv),
|
||||
console(c),
|
||||
cheats(ch),
|
||||
game(g),
|
||||
video(v),
|
||||
stats(s),
|
||||
notifications(n),
|
||||
window(sw),
|
||||
audio(a),
|
||||
keys(k),
|
||||
section(sec) {}
|
||||
};
|
||||
|
||||
extern Options options;
|
||||
|
||||
// Crea e inicializa las opciones del programa
|
||||
void initOptions();
|
||||
|
||||
// Carga las opciones desde un fichero
|
||||
bool loadOptionsFromFile(const std::string& file_path);
|
||||
|
||||
// Guarda las opciones a un fichero
|
||||
bool saveOptionsToFile(const std::string& file_path);
|
||||
1118
source2/Game/Gameplay/room.cpp
Normal file
1118
source2/Game/Gameplay/room.cpp
Normal file
File diff suppressed because it is too large
Load Diff
241
source2/Game/Gameplay/room.h
Normal file
241
source2/Game/Gameplay/room.h
Normal file
@@ -0,0 +1,241 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "enemy.h" // Para EnemyData
|
||||
#include "item.h" // Para ItemData
|
||||
#include "utils.h" // Para LineHorizontal, LineDiagonal, LineVertical
|
||||
class SSprite; // lines 12-12
|
||||
class Surface; // lines 13-13
|
||||
struct ScoreboardData; // lines 15-15
|
||||
|
||||
enum class TileType {
|
||||
EMPTY,
|
||||
WALL,
|
||||
PASSABLE,
|
||||
SLOPE_L,
|
||||
SLOPE_R,
|
||||
KILL,
|
||||
ANIMATED
|
||||
};
|
||||
|
||||
enum class RoomBorder : int {
|
||||
TOP = 0,
|
||||
RIGHT = 1,
|
||||
BOTTOM = 2,
|
||||
LEFT = 3
|
||||
};
|
||||
|
||||
struct AnimatedTile {
|
||||
std::shared_ptr<SSprite> sprite; // SSprite para dibujar el tile
|
||||
int x_orig; // Poicion X donde se encuentra el primer tile de la animacion en la tilesheet
|
||||
};
|
||||
|
||||
struct RoomData {
|
||||
std::string number; // Numero de la habitación
|
||||
std::string name; // Nombre de la habitación
|
||||
std::string bg_color; // Color de fondo de la habitación
|
||||
std::string border_color; // Color del borde de la pantalla
|
||||
std::string item_color1; // Color 1 para los items de la habitación
|
||||
std::string item_color2; // Color 2 para los items de la habitación
|
||||
std::string upper_room; // Identificador de la habitación que se encuentra arriba
|
||||
std::string lower_room; // Identificador de la habitación que se encuentra abajp
|
||||
std::string left_room; // Identificador de la habitación que se encuentra a la izquierda
|
||||
std::string right_room; // Identificador de la habitación que se encuentra a la derecha
|
||||
std::string tile_set_file; // Imagen con los graficos para la habitación
|
||||
std::string tile_map_file; // Fichero con el mapa de indices de tile
|
||||
int conveyor_belt_direction; // Sentido en el que arrastran las superficies automáticas de la habitación
|
||||
std::vector<int> tile_map; // Indice de los tiles a dibujar en la habitación
|
||||
std::vector<EnemyData> enemies; // Listado con los enemigos de la habitación
|
||||
std::vector<ItemData> items; // Listado con los items que hay en la habitación
|
||||
};
|
||||
|
||||
// Carga las variables desde un fichero de mapa
|
||||
RoomData loadRoomFile(const std::string& file_path, bool verbose = false);
|
||||
|
||||
// Carga las variables y texturas desde un fichero de mapa de tiles
|
||||
std::vector<int> loadRoomTileFile(const std::string& file_path, bool verbose = false);
|
||||
|
||||
// Asigna variables a una estructura RoomData
|
||||
bool setRoom(RoomData* room, const std::string& key, const std::string& value);
|
||||
|
||||
// Asigna variables a una estructura EnemyData
|
||||
bool setEnemy(EnemyData* enemy, const std::string& key, const std::string& value);
|
||||
|
||||
// Asigna variables a una estructura ItemData
|
||||
bool setItem(ItemData* item, const std::string& key, const std::string& value);
|
||||
|
||||
class Room {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int TILE_SIZE_ = 8; // Ancho del tile en pixels
|
||||
static constexpr int MAP_WIDTH_ = 32; // Ancho del mapa en tiles
|
||||
static constexpr int MAP_HEIGHT_ = 16; // Alto del mapa en tiles
|
||||
|
||||
// Objetos y punteros
|
||||
std::vector<std::shared_ptr<Enemy>> enemies_; // Listado con los enemigos de la habitación
|
||||
std::vector<std::shared_ptr<Item>> items_; // Listado con los items que hay en la habitación
|
||||
std::shared_ptr<Surface> surface_; // Textura con los graficos de la habitación
|
||||
std::shared_ptr<Surface> map_surface_; // Textura para dibujar el mapa de la habitación
|
||||
std::shared_ptr<ScoreboardData> data_; // Puntero a los datos del marcador
|
||||
|
||||
// Variables
|
||||
std::string number_; // Numero de la habitación
|
||||
std::string name_; // Nombre de la habitación
|
||||
std::string bg_color_; // Color de fondo de la habitación
|
||||
std::string border_color_; // Color del borde de la pantalla
|
||||
std::string item_color1_; // Color 1 para los items de la habitación
|
||||
std::string item_color2_; // Color 2 para los items de la habitación
|
||||
std::string upper_room_; // Identificador de la habitación que se encuentra arriba
|
||||
std::string lower_room_; // Identificador de la habitación que se encuentra abajp
|
||||
std::string left_room_; // Identificador de la habitación que se encuentra a la izquierda
|
||||
std::string right_room_; // Identificador de la habitación que se encuentra a la derecha
|
||||
std::string tile_set_file_; // Imagen con los graficos para la habitación
|
||||
std::string tile_map_file_; // Fichero con el mapa de indices de tile
|
||||
std::vector<int> tile_map_; // Indice de los tiles a dibujar en la habitación
|
||||
int conveyor_belt_direction_; // Sentido en el que arrastran las superficies automáticas de la habitación
|
||||
std::vector<LineHorizontal> bottom_floors_; // Lista con las superficies inferiores de la habitación
|
||||
std::vector<LineHorizontal> top_floors_; // Lista con las superficies superiores de la habitación
|
||||
std::vector<LineVertical> left_walls_; // Lista con las superficies laterales de la parte izquierda de la habitación
|
||||
std::vector<LineVertical> right_walls_; // Lista con las superficies laterales de la parte derecha de la habitación
|
||||
std::vector<LineDiagonal> left_slopes_; // Lista con todas las rampas que suben hacia la izquierda
|
||||
std::vector<LineDiagonal> right_slopes_; // Lista con todas las rampas que suben hacia la derecha
|
||||
int counter_; // Contador para lo que haga falta
|
||||
bool is_paused_; // Indica si el mapa esta en modo pausa
|
||||
std::vector<AnimatedTile> animated_tiles_; // Vector con los indices de tiles animados
|
||||
std::vector<LineHorizontal> conveyor_belt_floors_; // Lista con las superficies automaticas de la habitación
|
||||
int tile_set_width_; // Ancho del tileset en tiles
|
||||
|
||||
void initializeRoom(const RoomData& room);
|
||||
|
||||
// Pinta el mapa de la habitación en la textura
|
||||
void fillMapTexture();
|
||||
|
||||
// Calcula las superficies inferiores
|
||||
void setBottomSurfaces();
|
||||
|
||||
// Calcula las superficies superiores
|
||||
void setTopSurfaces();
|
||||
|
||||
// Calcula las superficies laterales izquierdas
|
||||
void setLeftSurfaces();
|
||||
|
||||
// Calcula las superficies laterales derechas
|
||||
void setRightSurfaces();
|
||||
|
||||
// Encuentra todas las rampas que suben hacia la izquierda
|
||||
void setLeftSlopes();
|
||||
|
||||
// Encuentra todas las rampas que suben hacia la derecha
|
||||
void setRightSlopes();
|
||||
|
||||
// Calcula las superficies automaticas
|
||||
void setAutoSurfaces();
|
||||
|
||||
// Localiza todos los tiles animados de la habitación
|
||||
void setAnimatedTiles();
|
||||
|
||||
// Actualiza los tiles animados
|
||||
void updateAnimatedTiles();
|
||||
|
||||
// Pinta los tiles animados en pantalla
|
||||
void renderAnimatedTiles();
|
||||
|
||||
// Devuelve el tipo de tile que hay en ese indice
|
||||
TileType getTile(int index);
|
||||
|
||||
// Abre la jail para poder entrar
|
||||
void openTheJail();
|
||||
|
||||
// Inicializa las superficies de colision
|
||||
void initRoomSurfaces();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Room(const std::string& room_path, std::shared_ptr<ScoreboardData> data);
|
||||
|
||||
// Destructor
|
||||
~Room() = default;
|
||||
|
||||
// Devuelve el nombre de la habitación
|
||||
const std::string& getName() const { return name_; }
|
||||
|
||||
// Devuelve el color de la habitación
|
||||
Uint8 getBGColor() const { return stringToColor(bg_color_); }
|
||||
|
||||
// Devuelve el color del borde
|
||||
Uint8 getBorderColor() const { return stringToColor(border_color_); }
|
||||
|
||||
// Dibuja el mapa en pantalla
|
||||
void renderMap();
|
||||
|
||||
// Dibuja los enemigos en pantalla
|
||||
void renderEnemies();
|
||||
|
||||
// Dibuja los objetos en pantalla
|
||||
void renderItems();
|
||||
|
||||
// Actualiza las variables y objetos de la habitación
|
||||
void update();
|
||||
|
||||
// Devuelve la cadena del fichero de la habitación contigua segun el borde
|
||||
std::string getRoom(RoomBorder border);
|
||||
|
||||
// Devuelve el tipo de tile que hay en ese pixel
|
||||
TileType getTile(SDL_FPoint point);
|
||||
|
||||
// Indica si hay colision con un enemigo a partir de un rectangulo
|
||||
bool enemyCollision(SDL_FRect& rect);
|
||||
|
||||
// Indica si hay colision con un objeto a partir de un rectangulo
|
||||
bool itemCollision(SDL_FRect& rect);
|
||||
|
||||
// Obten el tamaño del tile
|
||||
int getTileSize() const { return TILE_SIZE_; }
|
||||
|
||||
// Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile
|
||||
int getSlopeHeight(SDL_FPoint p, TileType slope);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkRightSurfaces(SDL_FRect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkLeftSurfaces(SDL_FRect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkTopSurfaces(SDL_FRect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkBottomSurfaces(SDL_FRect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkAutoSurfaces(SDL_FRect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkTopSurfaces(SDL_FPoint* p);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkAutoSurfaces(SDL_FPoint* p);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkLeftSlopes(const LineVertical* line);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkLeftSlopes(SDL_FPoint* p);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkRightSlopes(const LineVertical* line);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkRightSlopes(SDL_FPoint* p);
|
||||
|
||||
// Pone el mapa en modo pausa
|
||||
void setPaused(bool value) { is_paused_ = value; };
|
||||
|
||||
// Obten la direccion de las superficies automaticas
|
||||
int getAutoSurfaceDirection() const { return conveyor_belt_direction_; }
|
||||
};
|
||||
29
source2/Game/Gameplay/room_tracker.cpp
Normal file
29
source2/Game/Gameplay/room_tracker.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "room_tracker.h"
|
||||
|
||||
// Comprueba si la habitación ya ha sido visitada
|
||||
bool RoomTracker::hasBeenVisited(const std::string &name)
|
||||
{
|
||||
for (const auto &l : list)
|
||||
{
|
||||
if (l == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Añade la habitación a la lista
|
||||
bool RoomTracker::addRoom(const std::string &name)
|
||||
{
|
||||
// Comprueba si la habitación ya ha sido visitada
|
||||
if (!hasBeenVisited(name))
|
||||
{
|
||||
// En caso contrario añádela a la lista
|
||||
list.push_back(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
24
source2/Game/Gameplay/room_tracker.h
Normal file
24
source2/Game/Gameplay/room_tracker.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
class RoomTracker
|
||||
{
|
||||
private:
|
||||
// Variables
|
||||
std::vector<std::string> list; // Lista con las habitaciones visitadas
|
||||
|
||||
// Comprueba si la habitación ya ha sido visitada
|
||||
bool hasBeenVisited(const std::string &name);
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
RoomTracker() = default;
|
||||
|
||||
// Destructor
|
||||
~RoomTracker() = default;
|
||||
|
||||
// Añade la habitación a la lista
|
||||
bool addRoom(const std::string &name);
|
||||
};
|
||||
163
source2/Game/Gameplay/scoreboard.cpp
Normal file
163
source2/Game/Gameplay/scoreboard.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "scoreboard.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "defines.h" // Para BLOCK
|
||||
#include "options.h" // Para Options, options, Cheat, OptionsGame
|
||||
#include "resource.h" // Para Resource
|
||||
#include "screen.h" // Para Screen
|
||||
#include "sprite/surface_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text
|
||||
#include "utils.h" // Para stringToColor
|
||||
|
||||
// Constructor
|
||||
Scoreboard::Scoreboard(std::shared_ptr<ScoreboardData> data)
|
||||
: item_surface_(Resource::get()->getSurface("items.gif")),
|
||||
data_(data),
|
||||
clock_(ClockData()) {
|
||||
const float SURFACE_WIDTH_ = options.game.width;
|
||||
constexpr float SURFACE_HEIGHT_ = 6.0F * BLOCK;
|
||||
|
||||
// Reserva memoria para los objetos
|
||||
auto player_texture = Resource::get()->getSurface(options.cheats.alternate_skin == Cheat::CheatState::ENABLED ? "player2.gif" : "player.gif");
|
||||
auto player_animations = Resource::get()->getAnimations(options.cheats.alternate_skin == Cheat::CheatState::ENABLED ? "player2.ani" : "player.ani");
|
||||
player_sprite_ = std::make_shared<SAnimatedSprite>(player_texture, player_animations);
|
||||
player_sprite_->setCurrentAnimation("walk_menu");
|
||||
|
||||
surface_ = std::make_shared<Surface>(SURFACE_WIDTH_, SURFACE_HEIGHT_);
|
||||
surface_dest_ = {0, options.game.height - SURFACE_HEIGHT_, SURFACE_WIDTH_, SURFACE_HEIGHT_};
|
||||
|
||||
// Inicializa las variables
|
||||
counter_ = 0;
|
||||
change_color_speed_ = 4;
|
||||
is_paused_ = false;
|
||||
paused_time_ = 0;
|
||||
paused_time_elapsed_ = 0;
|
||||
items_color_ = stringToColor("white");
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<std::string> COLORS = {"blue", "magenta", "green", "cyan", "yellow", "white", "bright_blue", "bright_magenta", "bright_green", "bright_cyan", "bright_yellow", "bright_white"};
|
||||
for (const auto& color : COLORS) {
|
||||
color_.push_back(stringToColor(color));
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta el objeto en pantalla
|
||||
void Scoreboard::render() {
|
||||
surface_->render(nullptr, &surface_dest_);
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void Scoreboard::update() {
|
||||
counter_++;
|
||||
player_sprite_->update();
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
updateItemsColor();
|
||||
|
||||
// Dibuja la textura
|
||||
fillTexture();
|
||||
|
||||
if (!is_paused_) {
|
||||
// Si está en pausa no se actualiza el reloj
|
||||
clock_ = getTime();
|
||||
}
|
||||
}
|
||||
|
||||
// Obtiene el tiempo transcurrido de partida
|
||||
Scoreboard::ClockData Scoreboard::getTime() {
|
||||
const Uint32 timeElapsed = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
|
||||
|
||||
ClockData time;
|
||||
time.hours = timeElapsed / 3600000;
|
||||
time.minutes = timeElapsed / 60000;
|
||||
time.seconds = timeElapsed / 1000;
|
||||
time.separator = (timeElapsed % 1000 <= 500) ? ":" : " ";
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
// Pone el marcador en modo pausa
|
||||
void Scoreboard::setPaused(bool value) {
|
||||
if (is_paused_ == value) {
|
||||
// Evita ejecutar lógica si el estado no cambia
|
||||
return;
|
||||
}
|
||||
|
||||
is_paused_ = value;
|
||||
|
||||
if (is_paused_) {
|
||||
// Guarda el tiempo actual al pausar
|
||||
paused_time_ = SDL_GetTicks();
|
||||
} else {
|
||||
// Calcula el tiempo pausado acumulado al reanudar
|
||||
paused_time_elapsed_ += SDL_GetTicks() - paused_time_;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
void Scoreboard::updateItemsColor() {
|
||||
if (!data_->jail_is_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (counter_ % 20 < 10) {
|
||||
items_color_ = stringToColor("white");
|
||||
} else {
|
||||
items_color_ = stringToColor("magenta");
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve la cantidad de minutos de juego transcurridos
|
||||
int Scoreboard::getMinutes() {
|
||||
return getTime().minutes;
|
||||
}
|
||||
|
||||
// Dibuja los elementos del marcador en la textura
|
||||
void Scoreboard::fillTexture() {
|
||||
// Empieza a dibujar en la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(surface_);
|
||||
|
||||
// Limpia la textura
|
||||
surface_->clear(stringToColor("black"));
|
||||
|
||||
// Anclas
|
||||
constexpr int LINE1 = BLOCK;
|
||||
constexpr int LINE2 = 3 * BLOCK;
|
||||
|
||||
// Dibuja las vidas
|
||||
const int desp = (counter_ / 40) % 8;
|
||||
const int frame = desp % 4;
|
||||
player_sprite_->setCurrentAnimationFrame(frame);
|
||||
player_sprite_->setPosY(LINE2);
|
||||
for (int i = 0; i < data_->lives; ++i) {
|
||||
player_sprite_->setPosX(8 + (16 * i) + desp);
|
||||
const int index = i % color_.size();
|
||||
player_sprite_->render(1, color_.at(index));
|
||||
}
|
||||
|
||||
// Muestra si suena la música
|
||||
if (data_->music) {
|
||||
const Uint8 c = data_->color;
|
||||
SDL_FRect clip = {0, 8, 8, 8};
|
||||
item_surface_->renderWithColorReplace(20 * BLOCK, LINE2, 1, c, &clip);
|
||||
}
|
||||
|
||||
// Escribe los textos
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
|
||||
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
|
||||
text->writeColored(BLOCK, LINE1, "Items collected ", data_->color);
|
||||
text->writeColored(17 * BLOCK, LINE1, ITEMS_TEXT, items_color_);
|
||||
text->writeColored(20 * BLOCK, LINE1, " Time ", data_->color);
|
||||
text->writeColored(26 * BLOCK, LINE1, TIME_TEXT, stringToColor("white"));
|
||||
|
||||
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
|
||||
text->writeColored(22 * BLOCK, LINE2, "Rooms", stringToColor("white"));
|
||||
text->writeColored(28 * BLOCK, LINE2, ROOMS_TEXT, stringToColor("white"));
|
||||
|
||||
// Deja el renderizador como estaba
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
108
source2/Game/Gameplay/scoreboard.h
Normal file
108
source2/Game/Gameplay/scoreboard.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
class SAnimatedSprite; // lines 10-10
|
||||
class Surface; // lines 11-11
|
||||
|
||||
struct ScoreboardData {
|
||||
int items; // Lleva la cuenta de los objetos recogidos
|
||||
int lives; // Lleva la cuenta de las vidas restantes del jugador
|
||||
int rooms; // Lleva la cuenta de las habitaciones visitadas
|
||||
bool music; // Indica si ha de sonar la música durante el juego
|
||||
Uint8 color; // Color para escribir el texto del marcador
|
||||
Uint32 ini_clock; // Tiempo inicial para calcular el tiempo transcurrido
|
||||
bool jail_is_open; // Indica si se puede entrar a la Jail
|
||||
|
||||
// Constructor por defecto
|
||||
ScoreboardData()
|
||||
: items(0),
|
||||
lives(0),
|
||||
rooms(0),
|
||||
music(true),
|
||||
color(0),
|
||||
ini_clock(0),
|
||||
jail_is_open(false) {}
|
||||
|
||||
// Constructor parametrizado
|
||||
ScoreboardData(int items, int lives, int rooms, bool music, Uint8 color, Uint32 ini_clock, bool jail_is_open)
|
||||
: items(items),
|
||||
lives(lives),
|
||||
rooms(rooms),
|
||||
music(music),
|
||||
color(color),
|
||||
ini_clock(ini_clock),
|
||||
jail_is_open(jail_is_open) {}
|
||||
};
|
||||
|
||||
class Scoreboard {
|
||||
private:
|
||||
struct ClockData {
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
std::string separator;
|
||||
|
||||
// Constructor por defecto
|
||||
ClockData()
|
||||
: hours(0),
|
||||
minutes(0),
|
||||
seconds(0),
|
||||
separator(":") {}
|
||||
|
||||
// Constructor parametrizado
|
||||
ClockData(int h, int m, int s, const std::string& sep)
|
||||
: hours(h),
|
||||
minutes(m),
|
||||
seconds(s),
|
||||
separator(sep) {}
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<SAnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador
|
||||
std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador
|
||||
std::shared_ptr<ScoreboardData> data_; // Contiene las variables a mostrar en el marcador
|
||||
std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador;
|
||||
|
||||
// Variables
|
||||
std::vector<Uint8> color_; // Vector con los colores del objeto
|
||||
int counter_; // Contador interno
|
||||
int change_color_speed_; // Cuanto mas alto, mas tarda en cambiar de color
|
||||
bool is_paused_; // Indica si el marcador esta en modo pausa
|
||||
Uint32 paused_time_; // Milisegundos que ha estado el marcador en pausa
|
||||
Uint32 paused_time_elapsed_; // Tiempo acumulado en pausa
|
||||
ClockData clock_; // Contiene las horas, minutos y segundos transcurridos desde el inicio de la partida
|
||||
Uint8 items_color_; // Color de la cantidad de items recogidos
|
||||
SDL_FRect surface_dest_; // Rectangulo donde dibujar la surface del marcador
|
||||
|
||||
// Obtiene el tiempo transcurrido de partida
|
||||
ClockData getTime();
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
void updateItemsColor();
|
||||
|
||||
// Dibuja los elementos del marcador en la surface
|
||||
void fillTexture();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
explicit Scoreboard(std::shared_ptr<ScoreboardData> data);
|
||||
|
||||
// Destructor
|
||||
~Scoreboard() = default;
|
||||
|
||||
// Pinta el objeto en pantalla
|
||||
void render();
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void update();
|
||||
|
||||
// Pone el marcador en modo pausa
|
||||
void setPaused(bool value);
|
||||
|
||||
// Devuelve la cantidad de minutos de juego transcurridos
|
||||
int getMinutes();
|
||||
};
|
||||
216
source2/Game/Gameplay/stats.cpp
Normal file
216
source2/Game/Gameplay/stats.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "stats.h"
|
||||
#include <fstream> // Para basic_ostream, basic_ifstream, basic_istream
|
||||
#include <sstream> // Para basic_stringstream
|
||||
#include "options.h" // Para Options, OptionsStats, options
|
||||
|
||||
// Constructor
|
||||
Stats::Stats(const std::string &file, const std::string &buffer)
|
||||
: bufferPath(buffer),
|
||||
filePath(file) {}
|
||||
|
||||
// Destructor
|
||||
Stats::~Stats()
|
||||
{
|
||||
// Vuelca los datos del buffer en la lista de estadisticas
|
||||
updateListFromBuffer();
|
||||
|
||||
// Calcula cual es la habitación con más muertes
|
||||
checkWorstNightmare();
|
||||
|
||||
// Guarda las estadísticas
|
||||
saveToFile(bufferPath, bufferList);
|
||||
saveToFile(filePath, list);
|
||||
|
||||
bufferList.clear();
|
||||
list.clear();
|
||||
dictionary.clear();
|
||||
}
|
||||
|
||||
// Inicializador
|
||||
void Stats::init()
|
||||
// Se debe llamar a este procedimiento una vez se haya creado el diccionario numero-nombre
|
||||
{
|
||||
loadFromFile(bufferPath, bufferList);
|
||||
loadFromFile(filePath, list);
|
||||
|
||||
// Vuelca los datos del buffer en la lista de estadisticas
|
||||
updateListFromBuffer();
|
||||
}
|
||||
|
||||
// Añade una muerte a las estadisticas
|
||||
void Stats::addDeath(const std::string &name)
|
||||
{
|
||||
// Primero busca si ya hay una entrada con ese nombre
|
||||
const int index = findByName(name, bufferList);
|
||||
if (index != -1)
|
||||
{
|
||||
bufferList[index].died++;
|
||||
}
|
||||
|
||||
// En caso contrario crea la entrada
|
||||
else
|
||||
{
|
||||
StatsData item;
|
||||
item.name = name;
|
||||
item.visited = 0;
|
||||
item.died = 1;
|
||||
bufferList.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Añade una visita a las estadisticas
|
||||
void Stats::addVisit(const std::string &name)
|
||||
{
|
||||
// Primero busca si ya hay una entrada con ese nombre
|
||||
const int index = findByName(name, bufferList);
|
||||
if (index != -1)
|
||||
{
|
||||
bufferList[index].visited++;
|
||||
}
|
||||
|
||||
// En caso contrario crea la entrada
|
||||
else
|
||||
{
|
||||
StatsData item;
|
||||
item.name = name;
|
||||
item.visited = 1;
|
||||
item.died = 0;
|
||||
bufferList.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Busca una entrada en la lista por nombre
|
||||
int Stats::findByName(const std::string &name, const std::vector<StatsData> &list)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
if (l.name == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Carga las estadisticas desde un fichero
|
||||
bool Stats::loadFromFile(const std::string &file_path, std::vector<StatsData> &list)
|
||||
{
|
||||
list.clear();
|
||||
|
||||
// Indicador de éxito en la carga
|
||||
bool success = true;
|
||||
|
||||
// Variables para manejar el fichero
|
||||
std::ifstream file(file_path);
|
||||
|
||||
// Si el fichero se puede abrir
|
||||
if (file.good())
|
||||
{
|
||||
std::string line;
|
||||
// Procesa el fichero linea a linea
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
// Comprueba que la linea no sea un comentario
|
||||
if (line.substr(0, 1) != "#")
|
||||
{
|
||||
StatsData stat;
|
||||
std::stringstream ss(line);
|
||||
std::string tmp;
|
||||
|
||||
// Obtiene el nombre
|
||||
getline(ss, tmp, ';');
|
||||
stat.name = tmp;
|
||||
|
||||
// Obtiene las visitas
|
||||
getline(ss, tmp, ';');
|
||||
stat.visited = std::stoi(tmp);
|
||||
|
||||
// Obtiene las muertes
|
||||
getline(ss, tmp, ';');
|
||||
stat.died = std::stoi(tmp);
|
||||
|
||||
list.push_back(stat);
|
||||
}
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
file.close();
|
||||
}
|
||||
|
||||
// El fichero no existe
|
||||
else
|
||||
{
|
||||
// Crea el fichero con los valores por defecto
|
||||
saveToFile(file_path, list);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Guarda las estadisticas en un fichero
|
||||
void Stats::saveToFile(const std::string &file_path, const std::vector<StatsData> &list)
|
||||
{
|
||||
// Crea y abre el fichero de texto
|
||||
std::ofstream file(file_path);
|
||||
|
||||
// Escribe en el fichero
|
||||
file << "# ROOM NAME;VISITS;DEATHS" << std::endl;
|
||||
for (const auto &item : list)
|
||||
{
|
||||
file << item.name << ";" << item.visited << ";" << item.died << std::endl;
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Calcula cual es la habitación con más muertes
|
||||
void Stats::checkWorstNightmare()
|
||||
{
|
||||
int deaths = 0;
|
||||
for (const auto &item : list)
|
||||
{
|
||||
if (item.died > deaths)
|
||||
{
|
||||
deaths = item.died;
|
||||
options.stats.worst_nightmare = item.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Añade una entrada al diccionario
|
||||
void Stats::addDictionary(const std::string &number, const std::string &name)
|
||||
{
|
||||
dictionary.push_back({number, name});
|
||||
}
|
||||
|
||||
// Vuelca los datos del buffer en la lista de estadisticas
|
||||
void Stats::updateListFromBuffer()
|
||||
{
|
||||
// Actualiza list desde bufferList
|
||||
for (const auto &buffer : bufferList)
|
||||
{
|
||||
int index = findByName(buffer.name, list);
|
||||
|
||||
if (index != -1)
|
||||
{ // Encontrado. Aumenta sus estadisticas
|
||||
list[index].visited += buffer.visited;
|
||||
list[index].died += buffer.died;
|
||||
}
|
||||
else
|
||||
{ // En caso contrario crea la entrada
|
||||
StatsData item;
|
||||
item.name = buffer.name;
|
||||
item.visited = buffer.visited;
|
||||
item.died = buffer.died;
|
||||
list.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
saveToFile(bufferPath, bufferList);
|
||||
saveToFile(filePath, list);
|
||||
}
|
||||
63
source2/Game/Gameplay/stats.h
Normal file
63
source2/Game/Gameplay/stats.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
class Stats
|
||||
{
|
||||
private:
|
||||
struct StatsData
|
||||
{
|
||||
std::string name; // Nombre de la habitación
|
||||
int visited; // Cuenta las veces que se ha visitado una habitación
|
||||
int died; // Cuenta las veces que se ha muerto en una habitación
|
||||
};
|
||||
|
||||
struct StatsDictionary
|
||||
{
|
||||
std::string number; // Numero de la habitación
|
||||
std::string name; // Nombre de la habitación
|
||||
};
|
||||
|
||||
// Variables
|
||||
std::vector<StatsDictionary> dictionary; // Lista con la equivalencia nombre-numero de habitacion
|
||||
std::vector<StatsData> bufferList; // Lista con las estadisticas temporales por habitación
|
||||
std::vector<StatsData> list; // Lista con las estadisticas completas por habitación
|
||||
std::string bufferPath; // Fichero con las estadísticas temporales
|
||||
std::string filePath; // Fichero con las estadísticas completas
|
||||
|
||||
// Busca una entrada en la lista por nombre
|
||||
int findByName(const std::string &name, const std::vector<StatsData> &list);
|
||||
|
||||
// Carga las estadisticas desde un fichero
|
||||
bool loadFromFile(const std::string &filePath, std::vector<StatsData> &list);
|
||||
|
||||
// Guarda las estadisticas en un fichero
|
||||
void saveToFile(const std::string &filePath, const std::vector<StatsData> &list);
|
||||
|
||||
// Calcula cual es la habitación con más muertes
|
||||
void checkWorstNightmare();
|
||||
|
||||
// Vuelca los datos del buffer en la lista de estadisticas
|
||||
void updateListFromBuffer();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Stats(const std::string &file, const std::string &buffer);
|
||||
|
||||
// Destructor
|
||||
~Stats();
|
||||
|
||||
// Inicializador
|
||||
// Se debe llamar a este procedimiento una vez se haya creado el diccionario numero-nombre
|
||||
void init();
|
||||
|
||||
// Añade una muerte a las estadisticas
|
||||
void addDeath(const std::string &name);
|
||||
|
||||
// Añade una visita a las estadisticas
|
||||
void addVisit(const std::string &name);
|
||||
|
||||
// Añade una entrada al diccionario
|
||||
void addDictionary(const std::string &number, const std::string &name);
|
||||
};
|
||||
Reference in New Issue
Block a user