449 lines
12 KiB
C++
449 lines
12 KiB
C++
#include "hiscore_table.h"
|
|
#include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
|
|
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_QUIT
|
|
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
|
|
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
|
#include <SDL2/SDL_video.h> // Para SDL_WINDOWEVENT_SIZE_CHANGED
|
|
#include <stdlib.h> // Para rand
|
|
#include <algorithm> // Para max
|
|
#include <functional> // Para function
|
|
#include <vector> // Para vector
|
|
#include "background.h" // Para Background
|
|
#include "fade.h" // Para Fade, FadeMode, FadeType
|
|
#include "global_inputs.h" // Para check, update
|
|
#include "input.h" // Para Input
|
|
#include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state
|
|
#include "lang.h" // Para getText
|
|
#include "manage_hiscore_table.h" // Para HiScoreEntry
|
|
#include "mouse.h" // Para handleEvent
|
|
#include "options.h" // Para Options, OptionsGame, options
|
|
#include "param.h" // Para Param, param, ParamGame, ParamFade
|
|
#include "path_sprite.h" // Para PathSprite, Path, PathType
|
|
#include "resource.h" // Para Resource
|
|
#include "screen.h" // Para Screen
|
|
#include "section.h" // Para Name, name, Options, options, Attr...
|
|
#include "sprite.h" // Para Sprite
|
|
#include "text.h" // Para Text, TEXT_COLOR, TEXT_SHADOW
|
|
#include "texture.h" // Para Texture
|
|
#include "utils.h" // Para Color, easeOutQuint, fade_color
|
|
|
|
// Constructor
|
|
HiScoreTable::HiScoreTable()
|
|
: renderer_(Screen::get()->getRenderer()),
|
|
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
|
fade_(std::make_unique<Fade>()),
|
|
background_(std::make_unique<Background>()),
|
|
counter_(0),
|
|
ticks_(0),
|
|
view_area_({0, 0, param.game.width, param.game.height}),
|
|
fade_mode_(FadeMode::IN),
|
|
background_fade_color_(Color(0, 0, 0))
|
|
{
|
|
// Inicializa el resto
|
|
section::name = section::Name::HI_SCORE_TABLE;
|
|
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
|
|
initFade();
|
|
initBackground();
|
|
createSprites();
|
|
}
|
|
|
|
// Destructor
|
|
HiScoreTable::~HiScoreTable()
|
|
{
|
|
SDL_DestroyTexture(backbuffer_);
|
|
}
|
|
|
|
// Actualiza las variables
|
|
void HiScoreTable::update()
|
|
{
|
|
constexpr int TICKS_SPEED = 15;
|
|
|
|
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 las posiciones de los sprites de texto
|
|
updateSprites();
|
|
|
|
// Actualiza el objeto screen
|
|
Screen::get()->update();
|
|
|
|
// Actualiza las variables de globalInputs
|
|
globalInputs::update();
|
|
|
|
// Actualiza el fondo
|
|
background_->update();
|
|
|
|
// Gestiona el fade
|
|
updateFade();
|
|
|
|
// Gestiona el contador y sus eventos
|
|
counter_++;
|
|
|
|
if (counter_ == 150)
|
|
{
|
|
background_->setColor(background_fade_color_.darken());
|
|
background_->setAlpha(96);
|
|
}
|
|
|
|
if (counter_ == COUNTER_END_)
|
|
{
|
|
fade_->activate();
|
|
}
|
|
|
|
// Dibuja los sprites en la textura
|
|
fillTexture();
|
|
}
|
|
}
|
|
|
|
// Dibuja los sprites en la textura
|
|
void HiScoreTable::fillTexture()
|
|
{
|
|
// 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
|
|
header_->render();
|
|
|
|
// Escribe los nombres de la tabla de puntuaciones
|
|
for (auto const &entry : entry_names_)
|
|
{
|
|
entry->render();
|
|
}
|
|
|
|
// 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()->render();
|
|
}
|
|
|
|
// Recarga todas las texturas
|
|
void HiScoreTable::reloadTextures()
|
|
{
|
|
}
|
|
|
|
// 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 el cursor
|
|
Mouse::handleEvent(event);
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
|
|
return;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Crea los sprites con los textos
|
|
void HiScoreTable::createSprites()
|
|
{
|
|
auto header_text = Resource::get()->getText("04b_25");
|
|
auto entry_text = Resource::get()->getText("smb2");
|
|
|
|
// Obtiene el tamaño de la textura
|
|
int backbuffer_width;
|
|
int backbuffer_height;
|
|
SDL_QueryTexture(backbuffer_, nullptr, nullptr, &backbuffer_width, &backbuffer_height);
|
|
|
|
// Hay 27 letras - 7 de puntos quedan 20 caracteres 20 - name_lenght 0 num_dots
|
|
constexpr int max_names = 10;
|
|
constexpr int space_between_header = 32;
|
|
const int space_between_lines = entry_text->getCharacterSize() * 2;
|
|
const int size = space_between_header + space_between_lines * (max_names - 1) + entry_text->getCharacterSize();
|
|
const int first_line = (param.game.height - size) / 2;
|
|
|
|
// Crea el sprite para el texto de cabecera
|
|
header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(TEXT_COLOR, lang::getText(42), -2, background_fade_color_.getInverse().lighten(25)));
|
|
header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), first_line);
|
|
|
|
// Crea los sprites para las entradas en la tabla de puntuaciones
|
|
const int animation = rand() % 4;
|
|
for (int i = 0; i < max_names; ++i)
|
|
{
|
|
const auto table_position = (i + 1 >= 10) ? format(i + 1) + ". " : " " + format(i + 1) + ". ";
|
|
const auto score = format(options.game.hi_score_table.at(i).score);
|
|
const auto num_dots = 25 - table_position.size() - options.game.hi_score_table.at(i).name.size() - score.size();
|
|
std::string dots;
|
|
for (int j = 0; j < (int)num_dots; ++j)
|
|
{
|
|
dots = dots + ".";
|
|
}
|
|
const auto line = table_position + options.game.hi_score_table.at(i).name + dots + score;
|
|
|
|
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, orange_color, 1, shdw_txt_color)));
|
|
switch (animation)
|
|
{
|
|
case 0: // Ambos lados alternativamente
|
|
{
|
|
if (i % 2 == 0)
|
|
{
|
|
entry_names_.back()->addPath(
|
|
-entry_names_.back()->getWidth(),
|
|
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
|
|
PathType::HORIZONTAL,
|
|
(i * space_between_lines) + first_line + space_between_header,
|
|
80,
|
|
easeOutQuint,
|
|
0);
|
|
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
|
|
}
|
|
else
|
|
{
|
|
entry_names_.back()->addPath(
|
|
backbuffer_width,
|
|
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
|
|
PathType::HORIZONTAL,
|
|
(i * space_between_lines) + first_line + space_between_header,
|
|
80,
|
|
easeOutQuint,
|
|
0);
|
|
entry_names_.back()->setPosition(backbuffer_width, 0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 1: // Entran por la izquierda
|
|
{
|
|
entry_names_.back()->addPath(
|
|
-entry_names_.back()->getWidth(),
|
|
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
|
|
PathType::HORIZONTAL,
|
|
(i * space_between_lines) + first_line + space_between_header,
|
|
80,
|
|
easeOutQuint,
|
|
0);
|
|
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
|
|
break;
|
|
}
|
|
|
|
case 2: // Entran por la derecha
|
|
{
|
|
entry_names_.back()->addPath(
|
|
backbuffer_width,
|
|
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
|
|
PathType::HORIZONTAL,
|
|
(i * space_between_lines) + first_line + space_between_header,
|
|
80,
|
|
easeOutQuint,
|
|
0);
|
|
entry_names_.back()->setPosition(backbuffer_width, 0);
|
|
break;
|
|
}
|
|
|
|
case 3: // Entran desde la parte inferior
|
|
{
|
|
entry_names_.back()->addPath(
|
|
backbuffer_height,
|
|
(i * space_between_lines) + first_line + space_between_header,
|
|
PathType::VERTICAL,
|
|
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
|
|
80,
|
|
easeOutQuint,
|
|
0);
|
|
entry_names_.back()->setPosition(0, backbuffer_height);
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza las posiciones de los sprites de texto
|
|
void HiScoreTable::updateSprites()
|
|
{
|
|
constexpr int init_counter = 190;
|
|
const int counter_between_entries = 16;
|
|
if (counter_ >= init_counter)
|
|
{
|
|
const int counter2 = counter_ - init_counter;
|
|
if (counter2 % counter_between_entries == 0)
|
|
{
|
|
int index = counter2 / counter_between_entries;
|
|
if (index < static_cast<int>(entry_names_.size()))
|
|
{
|
|
entry_names_.at(index)->enable();
|
|
}
|
|
}
|
|
}
|
|
for (auto const &entry : entry_names_)
|
|
{
|
|
entry->update();
|
|
}
|
|
}
|
|
|
|
// Inicializa el fade
|
|
void HiScoreTable::initFade()
|
|
{
|
|
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
|
|
fade_->setType(FadeType::RANDOM_SQUARE);
|
|
fade_->setPostDuration(param.fade.post_duration);
|
|
fade_->setMode(fade_mode_);
|
|
fade_->activate();
|
|
}
|
|
|
|
// Inicializa el fondo
|
|
void HiScoreTable::initBackground()
|
|
{
|
|
background_->setPos(param.game.game_area.rect);
|
|
background_->setCloudsSpeed(-0.1f);
|
|
|
|
const int lucky = rand() % 3;
|
|
//const int lucky = 2;
|
|
switch (lucky)
|
|
{
|
|
case 0: // Fondo verde
|
|
{
|
|
background_->setGradientNumber(2);
|
|
background_->setTransition(0.0f);
|
|
background_->setSunProgression(1.0f);
|
|
background_->setMoonProgression(0.4f);
|
|
background_fade_color_ = Color(0x00, 0x79, 0x6b);
|
|
break;
|
|
}
|
|
|
|
case 1: // Fondo naranja
|
|
{
|
|
background_->setGradientNumber(1);
|
|
background_->setTransition(0.0f);
|
|
background_->setSunProgression(0.65f);
|
|
background_->setMoonProgression(0.0f);
|
|
background_fade_color_ = Color(0xff, 0x6b, 0x97);
|
|
break;
|
|
}
|
|
|
|
case 2: // Fondo azul
|
|
{
|
|
background_->setGradientNumber(0);
|
|
background_->setTransition(0.0f);
|
|
background_->setSunProgression(0.0f);
|
|
background_->setMoonProgression(0.0f);
|
|
background_fade_color_ = Color(0x02, 0x88, 0xd1);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} |