271 lines
9.3 KiB
C++
271 lines
9.3 KiB
C++
#include "game/scenes/instructions.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <algorithm> // for max
|
|
#include <iostream> // for char_traits, basic_ostream, operator<<
|
|
#include <string> // for basic_string
|
|
|
|
#include "core/audio/audio.hpp" // for Audio::update
|
|
#include "core/input/global_inputs.hpp" // for GlobalInputs::handle
|
|
#include "core/input/input.h" // for Input, REPEAT_FALSE, InputAction
|
|
#include "core/locale/lang.h" // for Lang
|
|
#include "core/rendering/screen.h" // for Screen
|
|
#include "core/rendering/sprite.h" // for Sprite
|
|
#include "core/rendering/text.h" // for Text, TXT_CENTER, TXT_COLOR, TXT_SHADOW
|
|
#include "core/rendering/texture.h" // for Texture
|
|
#include "core/resources/resource.h"
|
|
#include "game/defaults.hpp" // for GAMECANVAS_CENTER_X, GAME...
|
|
#include "utils/utils.h" // for Color, Section
|
|
|
|
// Constructor
|
|
Instructions::Instructions(SDL_Renderer *renderer, Section *section) {
|
|
// Copia los punteros
|
|
this->renderer_ = renderer;
|
|
this->section_ = section;
|
|
|
|
// Texturas (handles compartidos de Resource)
|
|
Resource *resource = Resource::get();
|
|
item_textures_.push_back(resource->getTexture("item_points1_disk.png"));
|
|
item_textures_.push_back(resource->getTexture("item_points2_gavina.png"));
|
|
item_textures_.push_back(resource->getTexture("item_points3_pacmar.png"));
|
|
item_textures_.push_back(resource->getTexture("item_clock.png"));
|
|
item_textures_.push_back(resource->getTexture("item_coffee.png"));
|
|
item_textures_.push_back(resource->getTexture("item_coffee_machine.png"));
|
|
|
|
event_handler_ = new SDL_Event();
|
|
|
|
sprite_ = new Sprite(0, 0, 16, 16, item_textures_[0], renderer);
|
|
text_ = resource->getText("smb2");
|
|
|
|
// Crea un backbuffer para el renderizador
|
|
backbuffer_ = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT);
|
|
if (backbuffer_ != nullptr) {
|
|
SDL_SetTextureScaleMode(backbuffer_, Texture::current_scale_mode);
|
|
} else {
|
|
std::cout << "Error: textTexture could not be created!\nSDL Error: " << SDL_GetError() << '\n';
|
|
}
|
|
|
|
// Inicializa variables
|
|
ticks_ = 0;
|
|
ticks_speed_ = 15;
|
|
manual_quit_ = false;
|
|
counter_ = 0;
|
|
counter_end_ = 600;
|
|
finished_ = false;
|
|
quit_requested_ = false;
|
|
}
|
|
|
|
// Destructor
|
|
Instructions::~Instructions() {
|
|
// itemTextures y text son propiedad de Resource — no liberar.
|
|
item_textures_.clear();
|
|
|
|
delete sprite_;
|
|
delete event_handler_;
|
|
|
|
SDL_DestroyTexture(backbuffer_);
|
|
}
|
|
|
|
// Actualiza las variables
|
|
void Instructions::update() {
|
|
// Bombea el stream de música: si no se llama, el buffer se vacía y la
|
|
// música se corta hasta que volvamos a una escena que sí lo haga.
|
|
Audio::update();
|
|
|
|
// Comprueba las entradas
|
|
checkInput();
|
|
|
|
// Actualiza las variables
|
|
if (SDL_GetTicks() - ticks_ > ticks_speed_) {
|
|
// Actualiza el contador de ticks
|
|
ticks_ = SDL_GetTicks();
|
|
|
|
if (mode_ == Mode::AUTO) { // Modo automático
|
|
counter_++;
|
|
|
|
if (counter_ == counter_end_) {
|
|
finished_ = true;
|
|
}
|
|
} else { // Modo manual
|
|
++counter_ %= 60000;
|
|
|
|
if (manual_quit_) {
|
|
finished_ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pinta en pantalla
|
|
void Instructions::render() {
|
|
// Pinta en pantalla
|
|
SDL_Rect window = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
|
|
SDL_Rect src_rect = {0, 0, 16, 16};
|
|
|
|
const Color ORANGE_COLOR = {0xFF, 0x7A, 0x00};
|
|
|
|
const SDL_Rect DEST_RECT1 = {60, 88 + (16 * 0), 16, 16}; // Disquito
|
|
const SDL_Rect DEST_RECT2 = {60, 88 + (16 * 1), 16, 16}; // Gavineixon
|
|
const SDL_Rect DEST_RECT3 = {60, 88 + (16 * 2), 16, 16}; // Pacmar
|
|
const SDL_Rect DEST_RECT4 = {60, 88 + (16 * 3), 16, 16}; // Time Stopper
|
|
const SDL_Rect DEST_RECT5 = {60, 88 + (16 * 4), 16, 16}; // Coffee
|
|
|
|
// Pinta en el backbuffer el texto y los sprites
|
|
SDL_SetRenderTarget(renderer_, backbuffer_);
|
|
SDL_SetRenderDrawColor(renderer_, BG_COLOR.r, BG_COLOR.g, BG_COLOR.b, 255);
|
|
SDL_RenderClear(renderer_);
|
|
|
|
// Escribe el texto
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 8, Lang::get()->getText(11), 1, ORANGE_COLOR, 1, SHADOW_COLOR);
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 24, Lang::get()->getText(12), 1, NO_COLOR, 1, SHADOW_COLOR);
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 34, Lang::get()->getText(13), 1, NO_COLOR, 1, SHADOW_COLOR);
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 48, Lang::get()->getText(14), 1, NO_COLOR, 1, SHADOW_COLOR);
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 58, Lang::get()->getText(15), 1, NO_COLOR, 1, SHADOW_COLOR);
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 75, Lang::get()->getText(16), 1, ORANGE_COLOR, 1, SHADOW_COLOR);
|
|
|
|
text_->writeShadowed(84, 92, Lang::get()->getText(17), SHADOW_COLOR);
|
|
text_->writeShadowed(84, 108, Lang::get()->getText(18), SHADOW_COLOR);
|
|
text_->writeShadowed(84, 124, Lang::get()->getText(19), SHADOW_COLOR);
|
|
text_->writeShadowed(84, 140, Lang::get()->getText(20), SHADOW_COLOR);
|
|
text_->writeShadowed(84, 156, Lang::get()->getText(21), SHADOW_COLOR);
|
|
|
|
if ((mode_ == Mode::MANUAL) && (counter_ % 50 > 14)) {
|
|
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, GAMECANVAS_HEIGHT - 12, Lang::get()->getText(22), 1, ORANGE_COLOR, 1, SHADOW_COLOR);
|
|
}
|
|
|
|
// Disquito
|
|
sprite_->setTexture(item_textures_[0]);
|
|
sprite_->setPos(DEST_RECT1);
|
|
src_rect.y = 16 * (((counter_ + 12) / 36) % 2);
|
|
sprite_->setSpriteClip(src_rect);
|
|
sprite_->render();
|
|
|
|
// Gavineixon
|
|
sprite_->setTexture(item_textures_[1]);
|
|
sprite_->setPos(DEST_RECT2);
|
|
src_rect.y = 16 * (((counter_ + 9) / 36) % 2);
|
|
sprite_->setSpriteClip(src_rect);
|
|
sprite_->render();
|
|
|
|
// Pacmar
|
|
sprite_->setTexture(item_textures_[2]);
|
|
sprite_->setPos(DEST_RECT3);
|
|
src_rect.y = 16 * (((counter_ + 6) / 36) % 2);
|
|
sprite_->setSpriteClip(src_rect);
|
|
sprite_->render();
|
|
|
|
// Time Stopper
|
|
sprite_->setTexture(item_textures_[3]);
|
|
sprite_->setPos(DEST_RECT4);
|
|
src_rect.y = 16 * (((counter_ + 3) / 36) % 2);
|
|
sprite_->setSpriteClip(src_rect);
|
|
sprite_->render();
|
|
|
|
// Coffee
|
|
sprite_->setTexture(item_textures_[4]);
|
|
sprite_->setPos(DEST_RECT5);
|
|
src_rect.y = 16 * (((counter_ + 0) / 36) % 2);
|
|
sprite_->setSpriteClip(src_rect);
|
|
sprite_->render();
|
|
|
|
// Cambia el destino de renderizado
|
|
SDL_SetRenderTarget(renderer_, nullptr);
|
|
|
|
// Prepara para empezar a dibujar en la textura de juego
|
|
Screen::get()->start();
|
|
|
|
// Limpia la pantalla
|
|
Screen::get()->clean(BG_COLOR);
|
|
|
|
// Establece la ventana del backbuffer
|
|
if (mode_ == Mode::AUTO) {
|
|
window.y = std::max(8, GAMECANVAS_HEIGHT - counter_ + 100);
|
|
} else {
|
|
window.y = 0;
|
|
}
|
|
|
|
// Copia el backbuffer al renderizador
|
|
SDL_FRect f_window = {(float)window.x, (float)window.y, (float)window.w, (float)window.h};
|
|
SDL_RenderTexture(renderer_, backbuffer_, nullptr, &f_window);
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
Screen::get()->blit();
|
|
}
|
|
|
|
// Comprueba los eventos
|
|
void Instructions::checkEvents() {
|
|
#ifndef __EMSCRIPTEN__
|
|
// Comprueba los eventos que hay en la cola
|
|
while (static_cast<int>(SDL_PollEvent(event_handler_)) != 0) {
|
|
// Evento de salida de la aplicación
|
|
if (event_handler_->type == SDL_EVENT_QUIT) {
|
|
quit_requested_ = true;
|
|
finished_ = true;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Comprueba las entradas
|
|
void Instructions::checkInput() {
|
|
#ifndef __EMSCRIPTEN__
|
|
if (Input::get()->checkInput(EXIT, REPEAT_FALSE)) {
|
|
quit_requested_ = true;
|
|
finished_ = true;
|
|
return;
|
|
}
|
|
#endif
|
|
if (GlobalInputs::handle()) { return; }
|
|
|
|
if (Input::get()->checkInput(PAUSE, REPEAT_FALSE) || Input::get()->checkInput(ACCEPT, REPEAT_FALSE) || Input::get()->checkInput(FIRE_LEFT, REPEAT_FALSE) || Input::get()->checkInput(FIRE_CENTER, REPEAT_FALSE) || Input::get()->checkInput(FIRE_RIGHT, REPEAT_FALSE)) {
|
|
if (mode_ == Mode::AUTO) {
|
|
finished_ = true;
|
|
} else {
|
|
if (counter_ > 30) {
|
|
manual_quit_ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bucle para la pantalla de instrucciones (compatibilidad)
|
|
void Instructions::run(Mode mode) {
|
|
start(mode);
|
|
|
|
while (!finished_) {
|
|
update();
|
|
checkEvents();
|
|
render();
|
|
}
|
|
|
|
// Aplica los cambios de sección según el resultado
|
|
if (quit_requested_) {
|
|
section_->name = SECTION_PROG_QUIT;
|
|
} else {
|
|
section_->name = SECTION_PROG_TITLE;
|
|
section_->subsection = (mode == Mode::AUTO) ? SUBSECTION_TITLE_1 : SUBSECTION_TITLE_3;
|
|
}
|
|
}
|
|
|
|
// Inicia las instrucciones (sin bucle)
|
|
void Instructions::start(Mode mode) {
|
|
mode_ = mode;
|
|
finished_ = false;
|
|
quit_requested_ = false;
|
|
manual_quit_ = false;
|
|
counter_ = 0;
|
|
ticks_ = 0;
|
|
}
|
|
|
|
// Indica si las instrucciones han terminado
|
|
auto Instructions::hasFinished() const -> bool {
|
|
return finished_;
|
|
}
|
|
|
|
// Indica si se ha solicitado salir de la aplicación
|
|
auto Instructions::isQuitRequested() const -> bool {
|
|
return quit_requested_;
|
|
}
|