Files
jaildoctors_dilemma/source/game/gameplay/cheevos.cpp

171 lines
6.0 KiB
C++

#include "game/gameplay/cheevos.hpp"
#include <SDL3/SDL.h>
#include <algorithm> // Para std::count_if
#include <cstddef> // Para NULL
#include <fstream> // Para basic_ostream, operator<<, basic_ofstream
#include <iostream> // Para cout, cerr
#include <utility>
#include "game/options.hpp" // Para Options, options
#include "game/ui/notifier.hpp" // 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
auto Cheevos::get() -> Cheevos* {
return Cheevos::cheevos;
}
// Constructor
Cheevos::Cheevos(std::string file)
: file_(std::move(file)) {
init();
loadFromFile();
}
// Destructor
Cheevos::~Cheevos() {
saveToFile();
}
// Inicializa los logros
void Cheevos::init() {
cheevos_list_.clear();
cheevos_list_.emplace_back(Achievement{.id = 1, .caption = "SHINY THINGS", .description = "Get 25% of the items", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 2, .caption = "HALF THE WORK", .description = "Get 50% of the items", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 3, .caption = "GETTING THERE", .description = "Get 75% of the items", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 4, .caption = "THE COLLECTOR", .description = "Get 100% of the items", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 5, .caption = "WANDERING AROUND", .description = "Visit 20 rooms", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 6, .caption = "I GOT LOST", .description = "Visit 40 rooms", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 7, .caption = "I LIKE TO EXPLORE", .description = "Visit all rooms", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 8, .caption = "FINISH THE GAME", .description = "Complete the game", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 9, .caption = "I WAS SUCKED BY A HOLE", .description = "Complete the game without entering the jail", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 10, .caption = "MY LITTLE PROJECTS", .description = "Complete the game with all items", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 11, .caption = "I LIKE MY MULTICOLOURED FRIENDS", .description = "Complete the game without dying", .icon = 2});
cheevos_list_.emplace_back(Achievement{.id = 12, .caption = "SHIT PROJECTS DONE FAST", .description = "Complete the game in under 30 minutes", .icon = 2});
}
// Busca un logro por id y devuelve el indice
auto Cheevos::find(int id) -> int {
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}, Notifier::Style::CHEEVO, -1, false);
// 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..." << '\n';
}
// Crea el fichero en modo escritura (binario)
std::ofstream new_file(file_, std::ios::binary);
if (new_file) {
if (Options::console) {
std::cout << "New " << file_ << " created!" << '\n';
}
// Guarda la información
for (const auto& cheevo : cheevos_list_) {
new_file.write(reinterpret_cast<const char*>(&cheevo.completed), sizeof(bool));
}
} else {
if (Options::console) {
std::cerr << "Error: Unable to create " << file_ << "!" << '\n';
}
}
}
// El fichero existe
else {
if (Options::console) {
std::cout << "Reading " << file_ << '\n';
}
// 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 (auto& i : cheevos_list_) {
SDL_WriteIO(file, &i.completed, sizeof(bool));
}
// Cierra el fichero
SDL_CloseIO(file);
} else {
if (Options::console) {
std::cout << "Error: Unable to save file! " << SDL_GetError() << '\n';
}
}
}
// Devuelve el número total de logros desbloqueados
auto Cheevos::getTotalUnlockedAchievements() -> int {
return std::count_if(cheevos_list_.begin(), cheevos_list_.end(), [](const auto& cheevo) { return cheevo.completed; });
}
// Elimina el estado "no obtenible"
void Cheevos::clearUnobtainableState() {
for (auto& cheevo : cheevos_list_) {
cheevo.obtainable = true;
}
}