diff --git a/source/cheevos.cpp b/source/cheevos.cpp index 3977f15..ca5d801 100644 --- a/source/cheevos.cpp +++ b/source/cheevos.cpp @@ -88,7 +88,7 @@ void Cheevos::unlock(int id) // 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}, cheevos_list_.at(index).icon); + Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", cheevos_list_.at(index).caption}, NotificationText::LEFT, cheevos_list_.at(index).icon); // Guardar el estado de los logros saveToFile(); } diff --git a/source/director.cpp b/source/director.cpp index b77b00a..f64861c 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -79,7 +79,7 @@ Director::Director(int argc, const char *argv[]) Screen::init(window_, renderer_); Screen::get()->setBorderColor(borderColor); Resource::init(); - Notifier::init(Asset::get()->get("notify.png"), Resource::get()->getText("smb2")); + Notifier::init("notify.png", "8bithud"); Input::init(Asset::get()->get("gamecontrollerdb.txt")); initInput(); Debug::init(); diff --git a/source/game.cpp b/source/game.cpp index 186db11..1d9669d 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -155,19 +155,19 @@ void Game::checkEvents() break; case SDL_SCANCODE_F6: - Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", "I LIKE MY MULTICOLOURED FRIENDS"}, 2); + Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", "I LIKE MY MULTICOLOURED FRIENDS"}, NotificationText::LEFT, 2, false, "F6"); break; case SDL_SCANCODE_F7: - Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", "I LIKE MY MULTICOLOURED FRIENDS"}, 3); + Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", "I LIKE MY MULTICOLOURED FRIENDS"}, NotificationText::LEFT, 3, false, "F7"); break; case SDL_SCANCODE_F8: - Notifier::get()->show({"JAILDESIGNER IS LOGGED IN", ""}, 4); + Notifier::get()->show({"JAILDESIGNER", "IS LOGGED IN"}, NotificationText::LEFT, 4, false); break; case SDL_SCANCODE_F9: - Notifier::get()->show({"JAILDESIGNER IS LOGGED IN", ""}, 5); + Notifier::get()->show({"JAILDESIGNER", "IS LOGGED IN"}, NotificationText::LEFT, 5, false); break; default: break; @@ -514,9 +514,9 @@ void Game::setScoreBoardColor() // Comprueba si ha finalizado el juego bool Game::checkEndGame() { - const bool isOnTheRoom = room_->getName() == "THE JAIL"; // Estar en la habitación que toca + const bool isOnTheRoom = room_->getName() == "THE JAIL"; // Estar en la habitación que toca const bool haveTheItems = board_->items >= int(total_items_ * 0.9f) || options.cheats.jail_is_open == Cheat::CheatState::ENABLED; // Con mas del 90% de los items recogidos - const bool isOnTheDoor = player_->getRect().x <= 128; // Y en la ubicación que toca (En la puerta) + const bool isOnTheDoor = player_->getRect().x <= 128; // Y en la ubicación que toca (En la puerta) if (haveTheItems) { diff --git a/source/global_inputs.cpp b/source/global_inputs.cpp index f3327e1..3b353fc 100644 --- a/source/global_inputs.cpp +++ b/source/global_inputs.cpp @@ -9,7 +9,22 @@ namespace globalInputs { - // Cambia la paleta + void quit() + { + const std::string code = options.section.section == Section::GAME ? "PRESS AGAIN TO RETURN TO MENU" : "PRESS AGAIN TO EXIT"; + auto code_found = stringInVector(Notifier::get()->getCodes(), code); + if (code_found) + { + // Si la notificación de salir está activa, cambia de sección + options.section.section = options.section.section == Section::GAME ? Section::TITLE : Section::QUIT; + } + else + { + // Si la notificación de salir no está activa, muestra la notificación + Notifier::get()->show({code}, NotificationText::CENTER, -1, true, code); + } + } + // Cambia la paleta de colores void switchPalette() { options.video.palette = options.video.palette == Palette::ZXSPECTRUM ? Palette::ZXARNE : Palette::ZXSPECTRUM; @@ -41,7 +56,7 @@ namespace globalInputs { if (Input::get()->checkInput(input_exit, REPEAT_FALSE)) { - options.section.section = Section::QUIT; + quit(); } else if (Input::get()->checkInput(input_accept, REPEAT_FALSE)) @@ -52,32 +67,37 @@ namespace globalInputs else if (Input::get()->checkInput(input_toggle_border, REPEAT_FALSE)) { Screen::get()->toggleBorder(); + Notifier::get()->show({"BORDER " + std::string(options.video.border.enabled ? "ENABLED" : "DISABLED")}, NotificationText::CENTER); } else if (Input::get()->checkInput(input_toggle_videomode, REPEAT_FALSE)) { Screen::get()->toggleVideoMode(); + Notifier::get()->show({"FULLSCREEN " + std::string(options.video.mode == 0 ? "DISABLED" : "ENABLED")}, NotificationText::CENTER); } else if (Input::get()->checkInput(input_window_dec_size, REPEAT_FALSE)) { Screen::get()->decWindowZoom(); + Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(options.window.zoom)}, NotificationText::CENTER); } else if (Input::get()->checkInput(input_window_inc_size, REPEAT_FALSE)) { Screen::get()->incWindowZoom(); + Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(options.window.zoom)}, NotificationText::CENTER); } else if (Input::get()->checkInput(input_toggle_shaders, REPEAT_FALSE)) { Screen::get()->toggleShaders(); - Notifier::get()->show({"HOLA"}); + Notifier::get()->show({"SHADERS " + std::string(options.video.shaders ? "ENABLED" : "DISABLED")}, NotificationText::CENTER); } else if (Input::get()->checkInput(input_toggle_palette, REPEAT_FALSE)) { switchPalette(); + Notifier::get()->show({"PALETTE " + std::string(options.video.palette == Palette::ZXSPECTRUM ? "ZX SPECTRUM" : "ZX ARNE")}, NotificationText::CENTER); } } } \ No newline at end of file diff --git a/source/notifier.cpp b/source/notifier.cpp index 3c3c523..4794f85 100644 --- a/source/notifier.cpp +++ b/source/notifier.cpp @@ -16,7 +16,7 @@ Notifier *Notifier::notifier_ = nullptr; // [SINGLETON] Crearemos el objeto con esta función estática -void Notifier::init(const std::string &icon_file, std::shared_ptr text) +void Notifier::init(const std::string &icon_file, const std::string &text) { Notifier::notifier_ = new Notifier(icon_file, text); } @@ -34,7 +34,7 @@ Notifier *Notifier::get() } // Constructor -Notifier::Notifier(std::string &icon_file, const std::string &text) +Notifier::Notifier(const std::string &icon_file, const std::string &text) : renderer_(Screen::get()->getRenderer()), icon_texture_(!icon_file.empty() ? Resource::get()->getTexture(icon_file) : nullptr), text_(Resource::get()->getText(text)), @@ -87,11 +87,11 @@ void Notifier::update() const float step = ((float)notifications_[i].counter / notifications_[i].travel_dist); const int alpha = 255 * step; - if (options.notifications.getVerticalPosition() == "TOP") + if (options.notifications.getVerticalPosition() == NotificationPosition::TOP) { notifications_[i].rect.y++; } - else + else if (options.notifications.getVerticalPosition() == NotificationPosition::BOTTOM) { notifications_[i].rect.y--; } @@ -119,11 +119,11 @@ void Notifier::update() const float step = (notifications_[i].counter / (float)notifications_[i].travel_dist); const int alpha = 255 * (1 - step); - if (options.notifications.getVerticalPosition() == "TOP") + if (options.notifications.getVerticalPosition() == NotificationPosition::TOP) { notifications_[i].rect.y--; } - else + else if (options.notifications.getVerticalPosition() == NotificationPosition::BOTTOM) { notifications_[i].rect.y++; } @@ -153,7 +153,7 @@ void Notifier::clearFinishedNotifications() } } -void Notifier::show(std::vector texts, int icon, const std::string &code) +void Notifier::show(std::vector texts, NotificationText text_is, int icon, bool can_be_removed, const std::string &code) { // Si no hay texto, acaba if (texts.empty()) @@ -181,43 +181,42 @@ void Notifier::show(std::vector texts, int icon, const std::string } // Inicializa variables - constexpr int icon_size = 16; - constexpr int padding_out = 1; const auto padding_in_h = text_->getCharacterSize(); const auto padding_in_v = text_->getCharacterSize() / 2; - const int icon_space = icon >= 0 ? icon_size + padding_in_h : 0; - const int width = text_->lenght(longest) + (padding_in_h * 2) + icon_space; + const int icon_space = icon >= 0 ? ICON_SIZE_ + padding_in_h : 0; + text_is = icon_space > 0 ? NotificationText::LEFT : text_is; + // const int width = text_->lenght(longest) + (padding_in_h * 2) + icon_space; + const int width = options.game.width - (PADDING_OUT_ * 2); const int height = (text_->getCharacterSize() * texts.size()) + (padding_in_v * 2); const auto shape = NotificationShape::SQUARED; // Posición horizontal auto desp_h = 0; - if (options.notifications.getHorizontalPosition() == "LEFT") + if (options.notifications.getHorizontalPosition() == NotificationPosition::LEFT) { - desp_h = padding_out; + desp_h = PADDING_OUT_; } - else if (options.notifications.getHorizontalPosition() == "CENTER") + else if (options.notifications.getHorizontalPosition() == NotificationPosition::CENTER) { desp_h = ((options.game.width / 2) - (width / 2)); } - else + else if (options.notifications.getHorizontalPosition() == NotificationPosition::RIGHT) { - desp_h = options.game.width - width - padding_out; + desp_h = options.game.width - width - PADDING_OUT_; } // Posición vertical - const int desp_v = (options.notifications.getVerticalPosition() == "TOP") ? padding_out : (options.game.height - height - padding_out); - + const int desp_v = (options.notifications.getVerticalPosition() == NotificationPosition::TOP) ? PADDING_OUT_ : options.game.height - height - PADDING_OUT_; // Offset - const auto travel_dist = height + padding_out; + const auto travel_dist = height + PADDING_OUT_; auto offset = 0; - if (options.notifications.getVerticalPosition() == "TOP") + if (options.notifications.getVerticalPosition() == NotificationPosition::TOP) { - offset = !notifications_.empty() ? notifications_.back().y + travel_dist : desp_v; + offset = !notifications_.empty() ? notifications_.back().y + notifications_.back().travel_dist : desp_v; } - else + else if (options.notifications.getVerticalPosition() == NotificationPosition::BOTTOM) { - offset = !notifications_.empty() ? notifications_.back().y - travel_dist : desp_v; + offset = !notifications_.empty() ? notifications_.back().y - notifications_.back().travel_dist : desp_v; } // Crea la notificacion @@ -225,11 +224,12 @@ void Notifier::show(std::vector texts, int icon, const std::string // Inicializa variables n.code = code; + n.can_be_removed = can_be_removed; n.y = offset; n.travel_dist = travel_dist; n.texts = texts; n.shape = shape; - int y_pos = offset + ((options.notifications.getVerticalPosition() == "TOP") ? -travel_dist : travel_dist); + int y_pos = offset + ((options.notifications.getVerticalPosition() == NotificationPosition::TOP) ? -travel_dist : travel_dist); n.rect = {desp_h, y_pos, width, height}; // Crea la textura @@ -266,9 +266,9 @@ void Notifier::show(std::vector texts, int icon, const std::string // Dibuja el icono de la notificación if (has_icons_ && icon >= 0 && texts.size() >= 2) { - auto sp = std::make_unique(icon_texture_, (SDL_Rect){0, 0, icon_size, icon_size}); - sp->setPosition({padding_in_h, padding_in_v, icon_size, icon_size}); - sp->setClip({icon_size * (icon % 10), icon_size * (icon / 10), icon_size, icon_size}); + auto sp = std::make_unique(icon_texture_, (SDL_Rect){0, 0, ICON_SIZE_, ICON_SIZE_}); + sp->setPosition({padding_in_h, padding_in_v, ICON_SIZE_, ICON_SIZE_}); + sp->setClip({ICON_SIZE_ * (icon % 10), ICON_SIZE_ * (icon / 10), ICON_SIZE_, ICON_SIZE_}); sp->render(); } @@ -277,7 +277,14 @@ void Notifier::show(std::vector texts, int icon, const std::string int iterator = 0; for (const auto &text : texts) { - text_->writeColored(padding_in_h + icon_space, padding_in_v + iterator * (text_->getCharacterSize() + 1), text, color); + if (text_is == NotificationText::LEFT) + { + text_->writeColored(padding_in_h + icon_space, padding_in_v + iterator * (text_->getCharacterSize() + 1), text, color); + } + else if (text_is == NotificationText::CENTER) + { + text_->writeDX(TEXT_CENTER | TEXT_COLOR, width / 2, padding_in_v + iterator * (text_->getCharacterSize() + 1), text, 1, color); + } ++iterator; } @@ -302,7 +309,10 @@ void Notifier::clearNotifications() { for (auto ¬ification : notifications_) { - notification.state = NotificationStatus::FINISHED; + if (notification.can_be_removed) + { + notification.state = NotificationStatus::FINISHED; + } } clearFinishedNotifications(); diff --git a/source/notifier.h b/source/notifier.h index feaec31..0975400 100644 --- a/source/notifier.h +++ b/source/notifier.h @@ -10,9 +10,19 @@ class Sprite; // lines 9-9 class Text; // lines 10-10 class Texture; // lines 11-11 +enum class NotificationText +{ + LEFT, + CENTER, +}; + class Notifier { private: + // Constantes + static constexpr int ICON_SIZE_ = 16; + static constexpr int PADDING_OUT_ = 0; + // [SINGLETON] Objeto notifier static Notifier *notifier_; @@ -42,11 +52,14 @@ private: int y; int travel_dist; std::string code; // Permite asignar un código a la notificación + bool can_be_removed; + int height; // Constructor explicit Notification() : texture(nullptr), sprite(nullptr), texts(), counter(0), state(NotificationStatus::RISING), - shape(NotificationShape::SQUARED), rect{0, 0, 0, 0}, y(0), travel_dist(0), code("") {} + shape(NotificationShape::SQUARED), rect{0, 0, 0, 0}, y(0), travel_dist(0), code(""), + can_be_removed(true), height(0) {} }; // Objetos y punteros @@ -71,14 +84,14 @@ private: // [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera // Constructor - Notifier(std::string icon_file, std::shared_ptr text); + Notifier(const std::string &icon_file, const std::string &text); // Destructor ~Notifier() = default; public: // [SINGLETON] Crearemos el objeto con esta función estática - static void init(const std::string &icon_file, std::shared_ptr text); + static void init(const std::string &icon_file, const std::string &text); // [SINGLETON] Destruiremos el objeto con esta función estática static void destroy(); @@ -93,7 +106,7 @@ public: void update(); // Muestra una notificación de texto por pantalla - void show(std::vector texts, int icon = -1, const std::string &code = std::string()); + void show(std::vector texts, NotificationText text_is = NotificationText::LEFT, int icon = -1, bool can_be_removed = true, const std::string &code = std::string()); // Indica si hay notificaciones activas bool isActive(); diff --git a/source/options.h b/source/options.h index 59cbc40..03c6c25 100644 --- a/source/options.h +++ b/source/options.h @@ -1,9 +1,9 @@ #pragma once -#include // for Uint32 -#include // for string, basic_string -#include "screen.h" // for ScreenFilter -#include "utils.h" // for Color, Palette +#include // for Uint32 +#include // for string, basic_string +#include "screen.h" // for ScreenFilter +#include "utils.h" // for Color, Palette // Secciones del programa enum class Section @@ -36,11 +36,15 @@ enum class NotificationPosition UPPER_LEFT, UPPER_CENTER, UPPER_RIGHT, - MIDDLE_LEFT, - MIDDLE_RIGHT, BOTTOM_LEFT, BOTTOM_CENTER, - BOTTOM_RIGHT + BOTTOM_RIGHT, + TOP, + BOTTOM, + LEFT, + RIGHT, + CENTER, + UNKNOWN, }; // Tipos de control de teclado @@ -72,7 +76,7 @@ constexpr NotificationPosition DEFAULT_NOTIFICATION_POSITION = NotificationPosit constexpr bool DEFAULT_NOTIFICATION_SOUND = true; // Sonido de las notificaciones por defecto const Color DEFAULT_NOTIFICATION_COLOR = Color(48, 48, 48); // Color de las notificaciones por defecto constexpr bool DEFAULT_CONSOLE = false; // Consola desactivada por defecto -constexpr std::string DEFAULT_VERSION = "1.09"; // Versión por defecto +constexpr const char *DEFAULT_VERSION = "1.09"; // Versión por defecto // Estructura para las opciones de las notificaciones struct OptionsNotification @@ -94,43 +98,42 @@ struct OptionsNotification color(c) {} // Método que devuelve la posición horizontal - std::string getHorizontalPosition() const + NotificationPosition getHorizontalPosition() const { switch (pos) { case NotificationPosition::UPPER_LEFT: - case NotificationPosition::MIDDLE_LEFT: case NotificationPosition::BOTTOM_LEFT: - return "LEFT"; + return NotificationPosition::LEFT; case NotificationPosition::UPPER_CENTER: case NotificationPosition::BOTTOM_CENTER: - return "CENTER"; + return NotificationPosition::CENTER; case NotificationPosition::UPPER_RIGHT: - case NotificationPosition::MIDDLE_RIGHT: case NotificationPosition::BOTTOM_RIGHT: - return "RIGHT"; + return NotificationPosition::RIGHT; + default: + return NotificationPosition::UNKNOWN; } - return "UNKNOWN"; + return NotificationPosition::UNKNOWN; } // Método que devuelve la posición vertical - std::string getVerticalPosition() const + NotificationPosition getVerticalPosition() const { switch (pos) { case NotificationPosition::UPPER_LEFT: case NotificationPosition::UPPER_CENTER: case NotificationPosition::UPPER_RIGHT: - return "UPPER"; - case NotificationPosition::MIDDLE_LEFT: - case NotificationPosition::MIDDLE_RIGHT: - return "MIDDLE"; + return NotificationPosition::TOP; case NotificationPosition::BOTTOM_LEFT: case NotificationPosition::BOTTOM_CENTER: case NotificationPosition::BOTTOM_RIGHT: - return "BOTTOM"; + return NotificationPosition::BOTTOM; + default: + return NotificationPosition::UNKNOWN; } - return "UNKNOWN"; + return NotificationPosition::UNKNOWN; } }; diff --git a/source/utils.cpp b/source/utils.cpp index 7ea85bf..6c4ad1f 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -518,4 +518,10 @@ void printWithDots(const std::string &text1, const std::string &text2, const std std::cout << text2; std::cout << text3 << std::endl; +} + +// Comprueba si una vector contiene una cadena +bool stringInVector(const std::vector &vec, const std::string &str) +{ + return std::find(vec.begin(), vec.end(), str) != vec.end(); } \ No newline at end of file diff --git a/source/utils.h b/source/utils.h index 05638a3..647ae99 100644 --- a/source/utils.h +++ b/source/utils.h @@ -122,4 +122,7 @@ std::string getFileName(const std::string &path); std::string getPath(const std::string &full_path); // Imprime por pantalla una linea de texto de tamaño fijo rellena con puntos -void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3); \ No newline at end of file +void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3); + +// Comprueba si una vector contiene una cadena +bool stringInVector(const std::vector &vec, const std::string &str); \ No newline at end of file