#include "game/gameplay/cheevos.hpp" #include #include // Para std::count_if #include // Para NULL #include // Para basic_ostream, operator<<, basic_ofstream #include // Para cout, cerr #include #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(&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(&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; } }