#include "ending2.h" #include // for SDL_BLENDMODE_BLEND #include // for SDL_GetTicks #include // for max, min, replace #include "animated_sprite.h" // for AnimatedSprite #include "asset.h" // for Asset #include "const.h" // for GAMECANVAS_HEIGHT, GAMECANVAS_CENTER_X #include "input.h" // for Input, REPEAT_FALSE, inputs_e #include "jail_audio.h" // for JA_SetVolume, JA_DeleteMusic, JA_Loa... #include "moving_sprite.h" // for MovingSprite #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_t, stringToColor, options_t #include "options.h" #include "global_inputs.h" #include "global_events.h" // Constructor Ending2::Ending2() : screen(Screen::get()), renderer(Screen::get()->getRenderer()), resource(Resource::get()), asset(Asset::get()), input(Input::get()) { // Reserva memoria para los punteros a objetos text = resource->getText("smb2.txt"); music = resource->getMusic("ending2.ogg"); // Inicializa variables counterEnabled = false; preCounter = 0; postCounter = 0; postCounterEnabled = false; options.section.section = Section::ENDING2; options.section.subsection = Subsection::NONE; ticks = 0; ticksSpeed = 15; distSpriteText = 8; distSpriteSprite = 0; despSpeed = -0.2f; firstCol = GAMECANVAS_FIRST_QUARTER_X + (GAMECANVAS_WIDTH / 16); secondCol = GAMECANVAS_THIRD_QUARTER_X - (GAMECANVAS_WIDTH / 16); // Inicializa el vector de colores const std::vector color_list = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"}; for (auto color : color_list) { colors.push_back(stringToColor(options.video.palette, color)); } // Cambia el color del borde screen->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 > ticksSpeed) { // Actualiza el contador de ticks ticks = SDL_GetTicks(); // Comprueba las entradas checkInput(); // Actualiza los contadores updateCounters(); if (counterEnabled) { // 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(); screen->update(); } } // Dibuja el final en pantalla void Ending2::render() { // Prepara para empezar a dibujar en la textura de juego screen->start(); // Limpia la pantalla screen->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(); const std::string txt = std::to_string(postCounter); // text->write(0, 192 - 8, txt); // Dibuja la cuadricula /*{ SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255); const int sw = maxSpriteWidth + 6; const int sh = maxSpriteHeight + 6; for (int i = 0; i < 256; i += sw) { SDL_RenderDrawLine(renderer, i, 0, i, 192); } for (int i = 0; i < 192; i += sh) { SDL_RenderDrawLine(renderer, 0, i, 255, i); } }*/ { // Dibuja una trama arriba y abajo SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF); for (int i = 0; i < 256; i += 2) { SDL_RenderDrawPoint(renderer, i + 0, 0); SDL_RenderDrawPoint(renderer, i + 1, 1); SDL_RenderDrawPoint(renderer, i + 0, 2); SDL_RenderDrawPoint(renderer, i + 1, 3); SDL_RenderDrawPoint(renderer, i, 4); SDL_RenderDrawPoint(renderer, i, 6); SDL_RenderDrawPoint(renderer, i + 0, 191); SDL_RenderDrawPoint(renderer, i + 1, 190); SDL_RenderDrawPoint(renderer, i + 0, 189); SDL_RenderDrawPoint(renderer, i + 1, 188); SDL_RenderDrawPoint(renderer, i, 187); SDL_RenderDrawPoint(renderer, i, 185); } // SDL_RenderDrawLine(renderer, 0, 1, 255, 1); // SDL_RenderDrawLine(renderer, 0, 3, 255, 3); // SDL_RenderDrawLine(renderer, 0, 188, 255, 188); // SDL_RenderDrawLine(renderer, 0, 190, 255, 190); } // Vuelca el contenido del renderizador en pantalla screen->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(music); while (options.section.section == Section::ENDING2) { update(); checkEvents(); render(); } JA_StopMusic(); JA_SetVolume(128); } // Actualiza los contadores void Ending2::updateCounters() { // Incrementa el contador if (preCounter < 200) { preCounter++; } else { counterEnabled = true; } if (postCounterEnabled) { postCounter++; } if (postCounter > 600) { options.section.section = Section::LOGO; options.section.subsection = Subsection::LOGO_TO_INTRO; } } // Inicializa la lista de sprites void Ending2::iniSpriteList() { // Reinicia el vector spriteList.clear(); // Añade los valores spriteList.push_back("bin"); spriteList.push_back("floppy"); spriteList.push_back("bird"); spriteList.push_back("chip"); spriteList.push_back("jeannine"); spriteList.push_back("spark"); spriteList.push_back("code"); spriteList.push_back("paco"); spriteList.push_back("elsa"); spriteList.push_back("z80"); spriteList.push_back("bell"); spriteList.push_back("dong"); spriteList.push_back("amstrad_cs"); spriteList.push_back("breakout"); spriteList.push_back("flying_arounder"); spriteList.push_back("stopped_arounder"); spriteList.push_back("walking_arounder"); spriteList.push_back("arounders_door"); spriteList.push_back("arounders_machine"); spriteList.push_back("abad"); spriteList.push_back("abad_bell"); spriteList.push_back("lord_abad"); spriteList.push_back("bat"); spriteList.push_back("batman_bell"); spriteList.push_back("batman_fire"); spriteList.push_back("batman"); spriteList.push_back("demon"); spriteList.push_back("heavy"); spriteList.push_back("dimallas"); spriteList.push_back("guitar"); spriteList.push_back("jailbattle_alien"); spriteList.push_back("jailbattle_human"); spriteList.push_back("jailer_#1"); spriteList.push_back("jailer_#2"); spriteList.push_back("jailer_#3"); spriteList.push_back("bry"); spriteList.push_back("upv_student"); spriteList.push_back("lamp"); spriteList.push_back("robot"); spriteList.push_back("congo"); spriteList.push_back("crosshair"); spriteList.push_back("tree_thing"); spriteList.push_back("matatunos"); spriteList.push_back("tuno"); spriteList.push_back("mummy"); spriteList.push_back("sam"); spriteList.push_back("qvoid"); spriteList.push_back("sigmasua"); spriteList.push_back("tv_panel"); spriteList.push_back("tv"); spriteList.push_back("spider"); spriteList.push_back("shock"); spriteList.push_back("wave"); spriteList.push_back("player"); } // Carga todos los sprites desde una lista void Ending2::loadSprites() { // Inicializa variables maxSpriteWidth = 0; maxSpriteHeight = 0; // Carga los sprites for (auto sl : spriteList) { sprites.emplace_back(std::make_shared(renderer, resource->getAnimation(sl + ".ani"))); maxSpriteWidth = std::max(sprites.back()->getWidth(), maxSpriteWidth); maxSpriteHeight = std::max(sprites.back()->getHeight(), maxSpriteHeight); } } // Actualiza los sprites void Ending2::updateSprites() { for (auto sprite : sprites) { sprite->update(); } } // Actualiza los sprites de texto void Ending2::updateTextSprites() { for (auto sprite : spriteTexts) { 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 { postCounterEnabled = 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 : spriteTexts) { 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 ? firstCol : secondCol; const int y = (i / 1) * (maxSpriteHeight + distSpriteText + text->getCharacterSize() + distSpriteSprite) + GAMECANVAS_HEIGHT + 40; const int w = sprites[i]->getWidth(); const int h = sprites[i]->getHeight(); const int dx = -(w / 2); const int dy = i % 1 == 0 ? maxSpriteHeight - h : (int)(maxSpriteHeight * 1.5f) - h; sprites[i]->setPosition({x + dx, y + dy, w, h}); sprites[i]->setVelY(despSpeed); } // 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() + maxSpriteHeight * 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 < (int)spriteList.size(); ++i) { // Calcula constantes std::string txt = spriteList[i]; std::replace(txt.begin(), txt.end(), '_', ' '); txt = txt == "player" ? "JAILDOCTOR" : txt; // Reemplaza el texto const int w = text->lenght(txt, 1); const int h = text->getCharacterSize(); const int x = i % 2 == 0 ? firstCol : secondCol; const int dx = -(w / 2); const int y = sprites[i]->getPosY() + sprites[i]->getHeight() + distSpriteText; // Cambia la posición del último sprite const int X = (i == (int)spriteList.size() - 1) ? GAMECANVAS_CENTER_X - (w / 2) : x + dx; // Crea la textura auto texture = std::make_shared(renderer); texture->createBlank(w, h); texture->setAsRenderTarget(renderer); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, txt); // Crea el sprite SDL_Rect pos = {X, y, w, h}; spriteTexts.emplace_back(std::make_shared(texture, pos)); spriteTexts.back()->setVelY(despSpeed); } } // 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"); // 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(renderer); texture->createBlank(w, h); texture->setAsRenderTarget(renderer); 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(despSpeed); } // Crea los últimos textos // El primer texto va a continuación del ultimo spriteText const int start = spriteTexts.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(renderer); texture->createBlank(w, h); texture->setAsRenderTarget(renderer); 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(despSpeed); } } // 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(postCounter, 500) - 500, 40) / 40.0f; const int index = (colors.size() - 1) * step; for (auto t : texts) { t->getTexture()->setColor(colors[index].r, colors[index].g, colors[index].b); } } // Actualiza el volumen de la musica void Ending2::updateMusicVolume() { if (postCounter > 0) { const float step = (600.0f - postCounter) / 600.0f; const int volume = 128 * step; JA_SetVolume(volume); } }