#include "ending2.h" #include // for SDL_BLENDMODE_BLEND #include // for SDL_PollEvent, SDL_Event #include // for SDL_Rect #include // for SDL_RenderDrawPoint, SDL_SetRenderDr... #include // for SDL_GetTicks #include // for max, min, replace #include "animated_sprite.h" // for AnimatedSprite #include "defines.h" // for GAMECANVAS_HEIGHT, GAMECANVAS_CENTER_X #include "global_events.h" // for check #include "global_inputs.h" // for check #include "jail_audio.h" // for JA_SetVolume, JA_PlayMusic, JA_StopM... #include "moving_sprite.h" // for MovingSprite #include "options.h" // for Options, options, OptionsVideo, Sect... #include "resource.h" // for Resource #include "screen.h" // for Screen #include "text.h" // for Text #include "texture.h" // for Texture #include "utils.h" // for Color, stringToColor // Constructor Ending2::Ending2() : counter_enabled_(false), pre_counter_(0), post_counter_(0), post_counter_enabled_(false), ticks_(0) { options.section.section = Section::ENDING2; options.section.subsection = Subsection::NONE; // Inicializa el vector de colores const std::vector color_list = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"}; for (const auto &color : color_list) { colors_.push_back(stringToColor(options.video.palette, color)); } // Cambia el color del borde Screen::get()->setBorderColor(stringToColor(options.video.palette, "black")); // Inicializa la lista de sprites iniSpriteList(); // Carga todos los sprites desde una lista loadSprites(); // Coloca los sprites en su sito placeSprites(); // Crea los sprites con las texturas con los textos createSpriteTexts(); // Crea los sprites con las texturas con los textos del final createTexts(); } // Actualiza el objeto void Ending2::update() { // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego if (SDL_GetTicks() - ticks_ > GAME_SPEED) { // Actualiza el contador de ticks ticks_ = SDL_GetTicks(); // Comprueba las entradas checkInput(); // Actualiza los contadores updateCounters(); if (counter_enabled_) { // Actualiza los sprites updateSprites(); // Actualiza los sprites de texto updateTextSprites(); // Actualiza los sprites de texto del final updateTexts(); } // Actualiza el fade final updateFinalFade(); // Actualiza el volumen de la musica updateMusicVolume(); // Actualiza el objeto Screen::get()->update(); } } // Dibuja el final en pantalla void Ending2::render() { // Prepara para empezar a dibujar en la textura de juego Screen::get()->start(); // Limpia la pantalla Screen::get()->clean(stringToColor(options.video.palette, "black")); // Dibuja los sprites renderSprites(); // Dibuja los sprites con el texto renderSpriteTexts(); // Dibuja los sprites con el texto del final renderTexts(); // Dibuja una trama arriba y abajo SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 0xFF); for (int i = 0; i < 256; i += 2) { SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 0, 0); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 1, 1); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 0, 2); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 1, 3); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 4); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 6); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 0, 191); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 1, 190); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 0, 189); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 1, 188); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 187); SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 185); } // Vuelca el contenido del renderizador en pantalla Screen::get()->render(); } // Comprueba el manejador de eventos void Ending2::checkEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { globalEvents::check(event); } } // Comprueba las entradas void Ending2::checkInput() { globalInputs::check(); } // Bucle principal void Ending2::run() { JA_PlayMusic(Resource::get()->getMusic("ending2.ogg")); while (options.section.section == Section::ENDING2) { update(); checkEvents(); render(); } JA_StopMusic(); JA_SetVolume(128); } // Actualiza los contadores void Ending2::updateCounters() { // Incrementa el contador if (pre_counter_ < 200) { pre_counter_++; } else { counter_enabled_ = true; } if (post_counter_enabled_) { post_counter_++; } if (post_counter_ > 600) { options.section.section = Section::LOGO; options.section.subsection = Subsection::LOGO_TO_INTRO; } } // Inicializa la lista de sprites void Ending2::iniSpriteList() { // Reinicia el vector sprite_list_.clear(); // Añade los valores sprite_list_.push_back("bin"); sprite_list_.push_back("floppy"); sprite_list_.push_back("bird"); sprite_list_.push_back("chip"); sprite_list_.push_back("jeannine"); sprite_list_.push_back("spark"); sprite_list_.push_back("code"); sprite_list_.push_back("paco"); sprite_list_.push_back("elsa"); sprite_list_.push_back("z80"); sprite_list_.push_back("bell"); sprite_list_.push_back("dong"); sprite_list_.push_back("amstrad_cs"); sprite_list_.push_back("breakout"); sprite_list_.push_back("flying_arounder"); sprite_list_.push_back("stopped_arounder"); sprite_list_.push_back("walking_arounder"); sprite_list_.push_back("arounders_door"); sprite_list_.push_back("arounders_machine"); sprite_list_.push_back("abad"); sprite_list_.push_back("abad_bell"); sprite_list_.push_back("lord_abad"); sprite_list_.push_back("bat"); sprite_list_.push_back("batman_bell"); sprite_list_.push_back("batman_fire"); sprite_list_.push_back("batman"); sprite_list_.push_back("demon"); sprite_list_.push_back("heavy"); sprite_list_.push_back("dimallas"); sprite_list_.push_back("guitar"); sprite_list_.push_back("jailbattle_alien"); sprite_list_.push_back("jailbattle_human"); sprite_list_.push_back("jailer_#1"); sprite_list_.push_back("jailer_#2"); sprite_list_.push_back("jailer_#3"); sprite_list_.push_back("bry"); sprite_list_.push_back("upv_student"); sprite_list_.push_back("lamp"); sprite_list_.push_back("robot"); sprite_list_.push_back("congo"); sprite_list_.push_back("crosshair"); sprite_list_.push_back("tree_thing"); sprite_list_.push_back("matatunos"); sprite_list_.push_back("tuno"); sprite_list_.push_back("mummy"); sprite_list_.push_back("sam"); sprite_list_.push_back("qvoid"); sprite_list_.push_back("sigmasua"); sprite_list_.push_back("tv_panel"); sprite_list_.push_back("tv"); sprite_list_.push_back("spider"); sprite_list_.push_back("shock"); sprite_list_.push_back("wave"); sprite_list_.push_back("player"); } // Carga todos los sprites desde una lista void Ending2::loadSprites() { // Inicializa variables sprite_max_width_ = 0; sprite_max_height_ = 0; // Carga los sprites for (const auto &sl : sprite_list_) { sprites_.emplace_back(std::make_shared(Resource::get()->getTexture(sl + ".png"), Resource::get()->getAnimations(sl + ".ani"))); sprite_max_width_ = std::max(sprites_.back()->getWidth(), sprite_max_width_); sprite_max_height_ = std::max(sprites_.back()->getHeight(), sprite_max_height_); } } // Actualiza los sprites void Ending2::updateSprites() { for (auto sprite : sprites_) { sprite->update(); } } // Actualiza los sprites de texto void Ending2::updateTextSprites() { for (auto sprite : sprite_texts_) { sprite->update(); } } // Actualiza los sprites de texto del final void Ending2::updateTexts() { if (texts_.back()->getPosY() > GAMECANVAS_CENTER_Y) { for (auto sprite : texts_) { sprite->update(); } } else { post_counter_enabled_ = true; } } // Dibuja los sprites void Ending2::renderSprites() { const Color color = stringToColor(options.video.palette, "red"); for (auto sprite : sprites_) { const bool a = sprite->getRect().y + sprite->getRect().h > 0; const bool b = sprite->getRect().y < GAMECANVAS_HEIGHT; if (a && b) { sprite->getTexture()->setColor(color.r, color.g, color.b); sprite->render(); } } // Pinta el ultimo elemento de otro color const Color c = stringToColor(options.video.palette, "white"); sprites_.back()->getTexture()->setColor(c.r, c.g, c.b); sprites_.back()->render(); } // Dibuja los sprites con el texto void Ending2::renderSpriteTexts() { const Color color = stringToColor(options.video.palette, "white"); for (auto sprite : sprite_texts_) { const bool a = sprite->getRect().y + sprite->getRect().h > 0; const bool b = sprite->getRect().y < GAMECANVAS_HEIGHT; if (a && b) { sprite->getTexture()->setColor(color.r, color.g, color.b); sprite->render(); } } } // Dibuja los sprites con el texto del final void Ending2::renderTexts() { for (auto sprite : texts_) { const bool a = sprite->getRect().y + sprite->getRect().h > 0; const bool b = sprite->getRect().y < GAMECANVAS_HEIGHT; if (a && b) { sprite->render(); } } } // Coloca los sprites en su sito void Ending2::placeSprites() { for (int i = 0; i < (int)sprites_.size(); ++i) { const int X = i % 2 == 0 ? FIRST_COL_ : SECOND_COL_; const int Y = (i / 1) * (sprite_max_height_ + DIST_SPRITE_TEXT_ + Resource::get()->getText("smb2")->getCharacterSize() + DIST_SPRITE_SPRITE_) + GAMECANVAS_HEIGHT + 40; const int W = sprites_.at(i)->getWidth(); const int H = sprites_.at(i)->getHeight(); const int DX = -(W / 2); const int DY = sprite_max_height_ - H; sprites_.at(i)->setPosition({X + DX, Y + DY, W, H}); sprites_.at(i)->setVelY(SPRITE_DESP_SPEED_); } // Recoloca el último sprite, que es el del jugador const int W = sprites_.back()->getWidth(); const int X = GAMECANVAS_CENTER_X - (W / 2); const int Y = sprites_.back()->getPosY() + sprite_max_height_ * 2; sprites_.back()->setPosX(X); sprites_.back()->setPosY(Y); sprites_.back()->setCurrentAnimation("walk"); } // Crea los sprites con las texturas con los textos void Ending2::createSpriteTexts() { // Crea los sprites de texto a partir de la lista for (int i = 0; i < static_cast(sprite_list_.size()); ++i) { auto text = Resource::get()->getText("smb2"); // Procesa y ajusta el texto del sprite actual std::string txt = sprite_list_[i]; std::replace(txt.begin(), txt.end(), '_', ' '); // Reemplaza '_' por ' ' if (txt == "player") { txt = "JAILDOCTOR"; // Reemplaza "player" por "JAILDOCTOR" } // Calcula las dimensiones del texto const int W = text->lenght(txt, 1); const int H = text->getCharacterSize(); // Determina la columna y la posición X del texto const int X = (i == static_cast(sprite_list_.size()) - 1) ? (GAMECANVAS_CENTER_X - (W / 2)) : ((i % 2 == 0 ? FIRST_COL_ : SECOND_COL_) - (W / 2)); // Calcula la posición Y del texto en base a la posición y altura del sprite const int Y = sprites_.at(i)->getPosY() + sprites_.at(i)->getHeight() + DIST_SPRITE_TEXT_; // Crea la textura auto texture = std::make_shared(Screen::get()->getRenderer()); texture->createBlank(W, H); texture->setAsRenderTarget(Screen::get()->getRenderer()); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, txt); // Crea el sprite SDL_Rect pos = {X, Y, W, H}; sprite_texts_.emplace_back(std::make_shared(texture, pos)); sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED_); } } // Crea los sprites con las texturas con los textos del final void Ending2::createTexts() { // Crea los primeros textos std::vector list; list.push_back("STARRING"); auto text = Resource::get()->getText("smb2"); // Crea los sprites de texto a partir de la lista for (int i = 0; i < (int)list.size(); ++i) { // Calcula constantes const int w = text->lenght(list[i], 1); const int h = text->getCharacterSize(); const int x = GAMECANVAS_CENTER_X; const int dx = -(w / 2); const int y = GAMECANVAS_HEIGHT + (text->getCharacterSize() * (i * 2)); // Crea la textura auto texture = std::make_shared(Screen::get()->getRenderer()); texture->createBlank(w, h); texture->setAsRenderTarget(Screen::get()->getRenderer()); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, list[i]); // Crea el sprite SDL_Rect pos = {x + dx, y, w, h}; texts_.emplace_back(std::make_shared(texture, pos)); texts_.back()->setVelY(SPRITE_DESP_SPEED_); } // Crea los últimos textos // El primer texto va a continuación del ultimo spriteText const int start = sprite_texts_.back()->getPosY() + text->getCharacterSize() * 15; list.clear(); list.push_back("THANK YOU"); list.push_back("FOR PLAYING!"); // Crea los sprites de texto a partir de la lista for (int i = 0; i < (int)list.size(); ++i) { // Calcula constantes const int w = text->lenght(list[i], 1); const int h = text->getCharacterSize(); const int x = GAMECANVAS_CENTER_X; const int dx = -(w / 2); const int y = start + (text->getCharacterSize() * (i * 2)); // Crea la textura auto texture = std::make_shared(Screen::get()->getRenderer()); texture->createBlank(w, h); texture->setAsRenderTarget(Screen::get()->getRenderer()); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, list[i]); // Crea el sprite SDL_Rect pos = {x + dx, y, w, h}; texts_.emplace_back(std::make_shared(texture, pos)); texts_.back()->setVelY(SPRITE_DESP_SPEED_); } } // Actualiza el fade final void Ending2::updateFinalFade() { // La variable step va de 0 a 40 en el tramo de postCounter que va de 500 a 540. Al dividirlo por 40, va de 0.0f a 1.0f const float STEP = std::min(std::max(post_counter_, 500) - 500, 40) / 40.0f; const int INDEX = (colors_.size() - 1) * STEP; for (const auto &text : texts_) { text->getTexture()->setColor(colors_.at(INDEX).r, colors_.at(INDEX).g, colors_.at(INDEX).b); } } // Actualiza el volumen de la musica void Ending2::updateMusicVolume() { if (post_counter_ > 0) { const float step = (600.0f - post_counter_) / 600.0f; const int volume = 128 * step; JA_SetVolume(volume); } }