Files
coffee-crisis/source/game/scenes/instructions.cpp
T

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 shdwTxtColor, 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_, bgColor.r, bgColor.g, bgColor.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, shdwTxtColor);
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 24, Lang::get()->getText(12), 1, noColor, 1, shdwTxtColor);
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 34, Lang::get()->getText(13), 1, noColor, 1, shdwTxtColor);
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 48, Lang::get()->getText(14), 1, noColor, 1, shdwTxtColor);
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 58, Lang::get()->getText(15), 1, noColor, 1, shdwTxtColor);
text_->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 75, Lang::get()->getText(16), 1, ORANGE_COLOR, 1, shdwTxtColor);
text_->writeShadowed(84, 92, Lang::get()->getText(17), shdwTxtColor);
text_->writeShadowed(84, 108, Lang::get()->getText(18), shdwTxtColor);
text_->writeShadowed(84, 124, Lang::get()->getText(19), shdwTxtColor);
text_->writeShadowed(84, 140, Lang::get()->getText(20), shdwTxtColor);
text_->writeShadowed(84, 156, Lang::get()->getText(21), shdwTxtColor);
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, shdwTxtColor);
}
// 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(bgColor);
// 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_;
}