Files
jaildoctors_dilemma/source/ending2.cpp

523 lines
15 KiB
C++

#include "ending2.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_RenderDrawPoint, SDL_SetRenderDr...
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <algorithm> // for max, min, replace
#include "s_animated_sprite.h" // for SAnimatedSprite
#include "defines.h" // for options.game.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 "s_moving_sprite.h" // for SMovingSprite
#include "options.h" // for Options, options, OptionsVideo, Sect...
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "text.h" // for Text
#include "surface.h" // for Surface
#include "utils.h" // for Color, stringToColor
#include <iostream>
// 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<std::string> COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
for (const auto &color : COLORS)
{
colors_.push_back(stringToColor(color));
}
// Cambia el color del borde
Screen::get()->setBorderColor(stringToColor("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 surface de juego
Screen::get()->start();
// Limpia la pantalla
Screen::get()->clear(stringToColor("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
Uint8 color = stringToColor("black");
auto surface = std::make_shared<Surface>(Screen::get()->getRenderSurfaceData(), 1, 1);
auto surfaceData = Screen::get()->getRenderSurfaceData();
for (int i = 0; i < 256; i += 2)
{
surface->putPixel(surfaceData, i + 0, 0, color);
surface->putPixel(surfaceData, i + 1, 1, color);
surface->putPixel(surfaceData, i + 0, 2, color);
surface->putPixel(surfaceData, i + 1, 3, color);
surface->putPixel(surfaceData, i, 4, color);
surface->putPixel(surfaceData, i, 6, color);
surface->putPixel(surfaceData, i + 0, 191, color);
surface->putPixel(surfaceData, i + 1, 190, color);
surface->putPixel(surfaceData, i + 0, 189, color);
surface->putPixel(surfaceData, i + 1, 188, color);
surface->putPixel(surfaceData, i, 187, color);
surface->putPixel(surfaceData, i, 185, color);
}
// 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 &file : sprite_list_)
{
sprites_.emplace_back(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface(file + ".gif"), Resource::get()->getAnimations(file + ".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 Uint8 colorA = stringToColor("red");
for (auto sprite : sprites_)
{
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
const bool B = sprite->getRect().y < options.game.height;
if (A && B)
{
sprite->render(1, colorA);
}
}
// Pinta el ultimo elemento de otro color
const Uint8 colorB = stringToColor("white");
sprites_.back()->render(1, colorB);
}
// Dibuja los sprites con el texto
void Ending2::renderSpriteTexts()
{
const Uint8 color = stringToColor("white");
for (auto sprite : sprite_texts_)
{
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
const bool B = sprite->getRect().y < options.game.height;
if (A && B)
{
sprite->render(1, color);
}
}
}
// 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 < options.game.height;
if (A && B)
{
sprite->render();
}
}
}
// Coloca los sprites en su sito
void Ending2::placeSprites()
{
for (int i = 0; i < static_cast<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_) + options.game.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)->setPos({X + DX, Y + DY, W, H});
sprites_.at(i)->setVelY(SPRITE_DESP_SPEED_);
}
// Recoloca el sprite del jugador, que es el último de la lista
const int X = (options.game.width - sprites_.back()->getWidth()) / 2;
const int Y = sprites_.back()->getPosY() + sprite_max_height_ * 2;
sprites_.back()->setPos(X, 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<int>(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<int>(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 surface
auto surface = std::make_shared<Surface>(Screen::get()->getRenderSurfaceData(), W, H);
Screen::get()->setRenderSurfaceData(surface);
text->write(0, 0, txt);
// Crea el sprite
SDL_Rect pos = {X, Y, W, H};
sprite_texts_.emplace_back(std::make_shared<SMovingSprite>(surface, pos));
sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED_);
Screen::get()->setRenderSurfaceData(nullptr);
}
}
// Crea los sprites con las texturas con los textos del final
void Ending2::createTexts()
{
// Crea los primeros textos
std::vector<std::string> 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 = options.game.height + (text->getCharacterSize() * (i * 2));
// Crea la surface
auto surface = std::make_shared<Surface>(Screen::get()->getRenderSurfaceData(), w, h);
Screen::get()->setRenderSurfaceData(surface);
text->write(0, 0, list[i]);
// Crea el sprite
SDL_Rect pos = {x + dx, y, w, h};
texts_.emplace_back(std::make_shared<SMovingSprite>(surface, pos));
texts_.back()->setVelY(SPRITE_DESP_SPEED_);
Screen::get()->setRenderSurfaceData(nullptr);
}
// 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 surface
auto surface = std::make_shared<Surface>(Screen::get()->getRenderSurfaceData(), w, h);
Screen::get()->setRenderSurfaceData(surface);
text->write(0, 0, list[i]);
// Crea el sprite
SDL_Rect pos = {x + dx, y, w, h};
texts_.emplace_back(std::make_shared<SMovingSprite>(surface, pos));
texts_.back()->setVelY(SPRITE_DESP_SPEED_);
Screen::get()->setRenderSurfaceData(nullptr);
}
}
// 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);
}
}