#include "gamestate_ending2.h" #include // Constructor Ending2::Ending2(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *asset, Input *input, options_t *options, section_t *section) { // Copia los punteros this->renderer = renderer; this->screen = screen; this->resource = resource; this->asset = asset; this->input = input; this->options = options; this->section = section; // Reserva memoria para los punteros a objetos eventHandler = new SDL_Event(); text = new Text(resource->getOffset("smb2.txt"), resource->getTexture("smb2.png"), renderer); music = JA_LoadMusic(asset->get("ending2.ogg").c_str()); // Inicializa variables counterEnabled = false; preCounter = 0; postCounter = 0; postCounterEnabled = false; section->name = SECTION_ENDING2; section->subsection = 0; 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 colorList = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"}; for (auto cl : colorList) { colors.push_back(stringToColor(options->palette, cl)); } // Cambia el color del borde screen->setBorderColor(stringToColor(options->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(); } // Destructor Ending2::~Ending2() { // Libera la memoria de los objetos delete eventHandler; delete text; JA_DeleteMusic(music); deleteSprites(); deleteSpriteTexts(); deleteTexts(); } // 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(); // Actualiza las notificaciones screen->updateNotifier(); } } // 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->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->blit(); } // Comprueba el manejador de eventos void Ending2::checkEvents() { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(eventHandler) != 0) { // Evento de salida de la aplicación if (eventHandler->type == SDL_QUIT) { section->name = SECTION_QUIT; break; } } } // Comprueba las entradas void Ending2::checkInput() { if (input->checkInput(input_exit, REPEAT_FALSE)) { section->name = SECTION_LOGO; section->subsection = SUBSECTION_LOGO_TO_INTRO; } else if (input->checkInput(input_toggle_border, REPEAT_FALSE)) { screen->switchBorder(); } else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { screen->switchVideoMode(); } else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { screen->decWindowSize(); } else if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { screen->incWindowSize(); } else if (input->checkInput(input_swap_palette, REPEAT_FALSE)) { switchPalette(); } } // Bucle principal void Ending2::run() { JA_PlayMusic(music); while (section->name == 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) { section->name = SECTION_LOGO; 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() { // Borra la memoria ocupada por los sprites deleteSprites(); // Inicializa variables maxSpriteWidth = 0; maxSpriteHeight = 0; // Carga los sprites for (auto sl : spriteList) { sprites.push_back(new AnimatedSprite(renderer, resource->getAnimation(sl + ".ani"))); maxSpriteWidth = std::max(sprites.back()->getAnimationClip(0, 0).w, maxSpriteWidth); maxSpriteHeight = std::max(sprites.back()->getAnimationClip(0, 0).h, 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_t color = stringToColor(options->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_t c = stringToColor(options->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_t color = stringToColor(options->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]->getAnimationClip(0, 0).w; const int h = sprites[i]->getAnimationClip(0, 0).h; const int dx = -(w / 2); const int dy = i % 1 == 0 ? maxSpriteHeight - h : (int)(maxSpriteHeight * 1.5f) - h; sprites[i]->setRect({x + dx, y + dy, w, h}); sprites[i]->setVelY(despSpeed); } // Recoloca el último sprite, que es el del jugador const int w = sprites.back()->getAnimationClip(0, 0).w; 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() { // Borra la memoria ocupada por los sprites con las texturas de los textos deleteSpriteTexts(); // 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 Texture *texture = new Texture(renderer); texture->createBlank(renderer, w, h, SDL_TEXTUREACCESS_TARGET); texture->setAsRenderTarget(renderer); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, txt); // Crea el sprite MovingSprite *sprite = new MovingSprite(X, y, w, h, 0.0f, despSpeed, 0.0f, 0.0f, texture, renderer); spriteTexts.push_back(sprite); } } // Crea los sprites con las texturas con los textos del final void Ending2::createTexts() { // Borra la memoria ocupada por los sprites con las texturas de los textos del final deleteTexts(); // 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 Texture *texture = new Texture(renderer); texture->createBlank(renderer, w, h, SDL_TEXTUREACCESS_TARGET); texture->setAsRenderTarget(renderer); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, list[i]); // Crea el sprite MovingSprite *sprite = new MovingSprite(x + dx, y, w, h, 0.0f, despSpeed, 0.0f, 0.0f, texture, renderer); texts.push_back(sprite); } // 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 Texture *texture = new Texture(renderer); texture->createBlank(renderer, w, h, SDL_TEXTUREACCESS_TARGET); texture->setAsRenderTarget(renderer); texture->setBlendMode(SDL_BLENDMODE_BLEND); text->write(0, 0, list[i]); // Crea el sprite MovingSprite *sprite = new MovingSprite(x + dx, y, w, h, 0.0f, despSpeed, 0.0f, 0.0f, texture, renderer); texts.push_back(sprite); } } // Borra la memoria ocupada por los sprites con las texturas de los textos void Ending2::deleteSpriteTexts() { for (auto sprite : spriteTexts) { delete sprite->getTexture(); delete sprite; } spriteTexts.clear(); } // Borra la memoria ocupada por los sprites void Ending2::deleteSprites() { for (auto sprite : sprites) { delete sprite; } sprites.clear(); } // Borra la memoria ocupada por los sprites con las texturas de los textos del final void Ending2::deleteTexts() { for (auto text : texts) { delete text; } texts.clear(); } // 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); } } // Cambia la paleta void Ending2::switchPalette() { options->palette = (options->palette == p_zxspectrum) ? p_zxarne : p_zxspectrum; }