Files
coffee_crisis_arcade_edition/source/hiscore_table.cpp
2024-10-20 11:37:26 +02:00

277 lines
7.3 KiB
C++

#include "hiscore_table.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event, SDL_QUIT
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <SDL2/SDL_video.h> // for SDL_WINDOWEVENT_SIZE_CHANGED
#include <algorithm> // for max
#include <vector> // for vector
#include "asset.h" // for Asset
#include "background.h" // for Background
#include "fade.h" // for Fade, FadeMode, FadeType
#include "global_inputs.h" // for check
#include "input.h" // for Input
#include "jail_audio.h" // for JA_GetMusicState, JA_Music_state
#include "lang.h" // for getText
#include "options.h" // for options
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "section.h" // for Name, name, Options, options
#include "text.h" // for Text, TEXT_CENTER, TEXT_SHADOW, TEXT...
#include "utils.h" // for Param, ParamGame, Color, HiScoreEntry
// Constructor
HiScoreTable::HiScoreTable()
{
// Copia punteros
renderer_ = Screen::get()->getRenderer();
// Objetos
fade_ = std::make_unique<Fade>();
background_ = std::make_unique<Background>(renderer_);
text_ = std::make_unique<Text>(Resource::get()->getTexture("smb2.gif"), Resource::get()->getTextFile("smb2.txt"));
// Crea un backbuffer para el renderizador
backbuffer_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
// Inicializa variables
section::name = section::Name::HI_SCORE_TABLE;
ticks_ = 0;
ticks_speed_ = 15;
counter_ = 0;
counter_end_ = 800;
view_area_ = {0, 0, param.game.width, param.game.height};
fade_mode_ = FadeMode::IN;
// Inicializa objetos
background_->setPos(param.game.game_area.rect);
background_->setCloudsSpeed(-0.1f);
background_->setGradientNumber(1);
background_->setTransition(0.8f);
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPost(param.fade.post_duration);
fade_->setMode(fade_mode_);
fade_->activate();
// Crea el contenido de la textura con la lista de puntuaciones
fillTexture();
}
// Destructor
HiScoreTable::~HiScoreTable()
{
SDL_DestroyTexture(backbuffer_);
}
// Actualiza las variables
void HiScoreTable::update()
{
// Actualiza las variables
if (SDL_GetTicks() - ticks_ > ticks_speed_)
{
// Actualiza el contador de ticks
ticks_ = SDL_GetTicks();
// Mantiene la música sonando
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
{
JA_PlayMusic(Resource::get()->getMusic("title.ogg"));
}
// Actualiza el objeto screen
Screen::get()->update();
// Actualiza el fondo
background_->update();
// Gestiona el fade
updateFade();
// Gestiona el contador y sus eventos
counter_++;
if (counter_ == 150)
{
background_->setColor({0, 0, 0});
background_->setAlpha(96);
}
if (counter_ == counter_end_)
{
fade_->activate();
}
}
}
// Crea el contenido de la textura con la lista de puntuaciones
void HiScoreTable::fillTexture()
{
// hay 27 letras - 7 de puntos quedan 20 caracteres 20 - name_lenght 0 num_dots
constexpr auto max_names = 10;
constexpr auto space_between_header = 32;
const auto space_between_lines = text_->getCharacterSize() * 2.0f;
const auto size = space_between_header + space_between_lines * (max_names - 1) + text_->getCharacterSize();
const auto first_line = (param.game.height - size) / 2;
// Pinta en el backbuffer el texto y los sprites
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_);
// Escribe el texto: Mejores puntuaciones
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, first_line, lang::getText(42), 1, orange_color, 1, shdw_txt_color);
// Escribe los nombres de la tabla de puntuaciones
for (int i = 0; i < max_names; ++i)
{
const auto name_lenght = options.game.hi_score_table[i].name.length();
const auto score = format(options.game.hi_score_table[i].score);
const auto score_lenght = score.size();
const auto num_dots = 25 - name_lenght - score_lenght;
std::string dots;
for (int j = 0; j < (int)num_dots; ++j)
{
dots = dots + ".";
}
const auto line = options.game.hi_score_table[i].name + dots + score;
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, (i * space_between_lines) + first_line + space_between_header, line, 1, orange_color, 1, shdw_txt_color);
}
// Cambia el destino de renderizado
SDL_SetRenderTarget(renderer_, temp);
}
// Pinta en pantalla
void HiScoreTable::render()
{
// Prepara para empezar a dibujar en la textura de juego
Screen::get()->start();
// Limpia la pantalla
Screen::get()->clean(bg_color);
// Pinta el fondo
background_->render();
// Establece la ventana del backbuffer
view_area_.y = std::max(0, param.game.height - counter_ + 100);
// Copia el backbuffer al renderizador
SDL_RenderCopy(renderer_, backbuffer_, nullptr, &view_area_);
// Renderiza el fade
fade_->render();
// Vuelca el contenido del renderizador en pantalla
Screen::get()->blit();
}
// Recarga todas las texturas
void HiScoreTable::reloadTextures()
{
text_->reLoadTexture();
fillTexture();
}
// Comprueba los eventos
void HiScoreTable::checkEvents()
{
// Comprueba los eventos que hay en la cola
SDL_Event event;
while (SDL_PollEvent(&event))
{
// Evento de salida de la aplicación
if (event.type == SDL_QUIT)
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_FROM_EVENT;
break;
}
// Comprueba si se ha cambiado el tamaño de la ventana
else if (event.type == SDL_WINDOWEVENT)
{
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
reloadTextures();
}
}
}
}
// Comprueba las entradas
void HiScoreTable::checkInput()
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed())
{
JA_StopMusic();
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
return;
}
// Comprueba el input para el resto de objetos
Screen::get()->checkInput();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
globalInputs::check();
}
// Bucle para la pantalla de instrucciones
void HiScoreTable::run()
{
while (section::name == section::Name::HI_SCORE_TABLE)
{
checkInput();
update();
checkEvents(); // Tiene que ir antes del render
render();
}
}
// Gestiona el fade
void HiScoreTable::updateFade()
{
fade_->update();
if (fade_->hasEnded() && fade_mode_ == FadeMode::IN)
{
fade_->reset();
fade_mode_ = FadeMode::OUT;
fade_->setMode(fade_mode_);
}
if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT)
{
section::name = section::Name::INSTRUCTIONS;
}
}
// Convierte un entero a un string con separadores de miles
std::string HiScoreTable::format(int number)
{
const std::string separator = ".";
const std::string score = std::to_string(number);
auto index = (int)score.size() - 1;
std::string result;
auto i = 0;
while (index >= 0)
{
result = score.at(index) + result;
index--;
i++;
if (i == 3)
{
i = 0;
result = separator + result;
}
}
return result;
}