#include "game/scenes/loading_screen.hpp" #include #include // Para rand #include "core/input/global_inputs.hpp" // Para check #include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/surface_sprite.hpp" // Para SSprite #include "core/resources/resource.hpp" // Para Resource #include "external/jail_audio.h" // Para JA_PlayMusic, JA_SetVolume, JA_StopMusic #include "game/options.hpp" // Para Options, options, SectionState, Options... #include "game/scene_manager.hpp" // Para SceneManager #include "utils/defines.hpp" // Para GAME_SPEED #include "utils/global_events.hpp" // Para check #include "utils/utils.hpp" // Para stringToColor, PaletteColor // Constructor LoadingScreen::LoadingScreen() : mono_loading_screen_surface_(Resource::get()->getSurface("loading_screen_bn.gif")), color_loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")), mono_loading_screen_sprite_(std::make_shared(mono_loading_screen_surface_, 0, 0, mono_loading_screen_surface_->getWidth(), mono_loading_screen_surface_->getHeight())), color_loading_screen_sprite_(std::make_shared(color_loading_screen_surface_, 0, 0, color_loading_screen_surface_->getWidth(), color_loading_screen_surface_->getHeight())), screen_surface_(std::make_shared(Options::game.width, Options::game.height)), delta_timer_(std::make_unique()), state_(LoadingState::PRE_LOADING), state_time_(0.0f), load_rect_{0, 0, 0, 1.0f} { // Configura la superficie donde se van a pintar los sprites screen_surface_->clear(static_cast(PaletteColor::WHITE)); // Inicializa variables SceneManager::current = SceneManager::Scene::LOADING_SCREEN; SceneManager::options = SceneManager::Options::NONE; // Inicializa el array de índices de líneas initLineIndexArray(); // Cambia el color del borde Screen::get()->setBorderColor(stringToColor("black")); } // Destructor LoadingScreen::~LoadingScreen() { JA_StopMusic(); } // Comprueba el manejador de eventos void LoadingScreen::checkEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { globalEvents::check(event); } } // Comprueba las entradas void LoadingScreen::checkInput() { globalInputs::check(); } // Inicializa el array de índices de líneas (imita el direccionamiento de memoria del Spectrum) void LoadingScreen::initLineIndexArray() { for (int i = 0; i < MONO_TOTAL_LINES; ++i) { if (i < 64) { // Primer bloque de 2K line_index_[i] = ((i % 8) * 8) + (i / 8); } else if (i < 128) { // Segundo bloque de 2K line_index_[i] = 64 + ((i % 8) * 8) + ((i - 64) / 8); } else { // Tercer bloque de 2K line_index_[i] = 128 + ((i % 8) * 8) + ((i - 128) / 8); } } } // Transiciona a un nuevo estado void LoadingScreen::transitionToState(LoadingState new_state) { state_ = new_state; state_time_ = 0.0f; // Acciones específicas al entrar en cada estado switch (new_state) { case LoadingState::PRE_LOADING: // No hay acción específica break; case LoadingState::LOADING_MONO: // Reproducir sonido de carga monocromática JA_PlayMusic(Resource::get()->getMusic("loading_sound2.ogg")); break; case LoadingState::LOADING_COLOR: // Reproducir sonido de carga en color JA_PlayMusic(Resource::get()->getMusic("loading_sound3.ogg")); break; case LoadingState::COMPLETE: // Transicionar a la pantalla de título SceneManager::current = SceneManager::Scene::TITLE; SceneManager::options = SceneManager::Options::TITLE_WITH_LOADING_SCREEN; JA_StopMusic(); break; } } // Actualiza el estado actual void LoadingScreen::updateState(float delta_time) { state_time_ += delta_time; // Solo PRE_LOADING transiciona por tiempo // LOADING_MONO y LOADING_COLOR transicionan cuando completan su progreso if (state_ == LoadingState::PRE_LOADING) { if (state_time_ >= PRE_LOADING_DURATION) { transitionToState(LoadingState::LOADING_MONO); } } } // Gestiona la carga monocromática (time-based simplificado) void LoadingScreen::updateMonoLoad(float delta_time) { // Calcular progreso lineal (0.0 - 1.0) float progress = state_time_ / LOADING_MONO_DURATION; progress = std::min(progress, 1.0f); // Calcular paso total actual (0-959) const int total_steps = MONO_TOTAL_LINES * MONO_STEPS_PER_LINE; // 192 * 5 = 960 const int current_step = static_cast(progress * total_steps); // Calcular línea y sub-paso const int current_line = current_step / MONO_STEPS_PER_LINE; // 0-191 const int current_substep = current_step % MONO_STEPS_PER_LINE; // 0-4 // Verificar si ha completado todas las líneas if (current_line >= MONO_TOTAL_LINES) { transitionToState(LoadingState::LOADING_COLOR); return; } // Calcular rectángulo de clip (con floats para mayor precisión) const float texture_width = static_cast(mono_loading_screen_surface_->getWidth()); const float clip_width = texture_width / MONO_STEPS_PER_LINE; const float clip_x = current_substep * clip_width; load_rect_.x = clip_x; load_rect_.y = static_cast(line_index_[current_line]); load_rect_.w = clip_width; load_rect_.h = 1.0f; // Configurar y dibujar sobre screen_surface_ mono_loading_screen_sprite_->setClip(load_rect_); mono_loading_screen_sprite_->setPosition(load_rect_); auto previous_renderer = Screen::get()->getRendererSurface(); Screen::get()->setRendererSurface(screen_surface_); mono_loading_screen_sprite_->render(1, stringToColor("black")); Screen::get()->setRendererSurface(previous_renderer); } // Gestiona la carga en color (time-based simplificado) void LoadingScreen::updateColorLoad(float delta_time) { // Calcular progreso lineal (0.0 - 1.0) float progress = state_time_ / LOADING_COLOR_DURATION; progress = std::min(progress, 1.0f); // Calcular iteración actual (el código original incrementaba de 2 en 2) const int total_iterations = COLOR_TOTAL_BLOCKS / 2; // 768 / 2 = 384 iteraciones const int current_iteration = static_cast(progress * total_iterations); // Convertir a bloque (incrementa de 2 en 2, empezando en 0) const int current_block = current_iteration * 2; // Verificar si ha completado todos los bloques if (current_block >= COLOR_TOTAL_BLOCKS) { transitionToState(LoadingState::COMPLETE); return; } // Calcular posición del bloque load_rect_.x = static_cast((current_block * COLOR_BLOCK_SPACING) % 256); load_rect_.y = static_cast((current_block / COLOR_BLOCKS_PER_ROW) * COLOR_BLOCK_SPACING); load_rect_.w = static_cast(COLOR_BLOCK_WIDTH); load_rect_.h = static_cast(COLOR_BLOCK_HEIGHT); // Configurar y dibujar sobre screen_surface_ color_loading_screen_sprite_->setClip(load_rect_); color_loading_screen_sprite_->setPosition(load_rect_); auto previous_renderer = Screen::get()->getRendererSurface(); Screen::get()->setRendererSurface(screen_surface_); color_loading_screen_sprite_->render(); Screen::get()->setRendererSurface(previous_renderer); } // Dibuja la pantalla de carga void LoadingScreen::renderLoad() { // El dibujo incremental ya se realiza en updateMonoLoad() y updateColorLoad() // Esta función ya no es necesaria, pero se mantiene por compatibilidad } // Dibuja el efecto de carga en el borde void LoadingScreen::renderBorder() { // Obtiene la Surface del borde auto border = Screen::get()->getBorderSurface(); // Pinta el borde de color azul border->clear(static_cast(PaletteColor::BLUE)); // Añade lineas amarillas const Uint8 COLOR = static_cast(PaletteColor::YELLOW); const int WIDTH = Options::game.width + (Options::video.border.width * 2); const int HEIGHT = Options::game.height + (Options::video.border.height * 2); bool draw_enabled = rand() % 2 == 0 ? true : false; int row = 0; while (row < HEIGHT) { const int ROW_HEIGHT = (rand() % 4) + 3; if (draw_enabled) { for (int i = row; i < row + ROW_HEIGHT; ++i) { border->drawLine(0, i, WIDTH, i, COLOR); } } row += ROW_HEIGHT; draw_enabled = !draw_enabled; } } // Actualiza las variables void LoadingScreen::update() { // Obtener delta time desde el último frame const float delta_time = delta_timer_->tick(); checkInput(); // Comprueba las entradas updateState(delta_time); // Actualiza el estado y gestiona transiciones // Actualizar la carga según el estado actual switch (state_) { case LoadingState::PRE_LOADING: // No hay animación de carga durante la pausa inicial break; case LoadingState::LOADING_MONO: updateMonoLoad(delta_time); break; case LoadingState::LOADING_COLOR: updateColorLoad(delta_time); break; case LoadingState::COMPLETE: // No hay más actualizaciones break; } renderLoad(); // Dibuja la pantalla de carga Screen::get()->update(); // Actualiza el objeto Screen } // Dibuja en pantalla void LoadingScreen::render() { if (Options::video.border.enabled) { // Dibuja el efecto de carga en el borde renderBorder(); } // Prepara para empezar a dibujar en la textura de juego Screen::get()->start(); Screen::get()->clearSurface(stringToColor("white")); // Copia la surface a la surface de Screen screen_surface_->render(0, 0); // Vuelca el contenido del renderizador en pantalla Screen::get()->render(); } // Bucle para el logo del juego void LoadingScreen::run() { // Inicia el sonido de carga JA_SetVolume(64); JA_PlayMusic(Resource::get()->getMusic("loading_sound1.ogg")); // Limpia la pantalla Screen::get()->start(); Screen::get()->clearRenderer(); Screen::get()->render(); while (SceneManager::current == SceneManager::Scene::LOADING_SCREEN) { update(); checkEvents(); render(); } JA_SetVolume(128); }