// IWYU pragma: no_include #include "director.h" #include // Para SDL_LogInfo, SDL_LogCategory, SDL_SetLogPriority, SDL_LogPriority, SDL_Quit #include // Para srand, exit, rand, EXIT_FAILURE #include // Para time #include // Para basic_ostream, operator<<, cerr, endl #include // Para make_unique, unique_ptr #include // Para span #include // Para runtime_error #include // Para allocator, char_traits, operator==, string, basic_string, operator+ #include "asset.h" // Para Asset #include "audio.h" // Para Audio #include "input.h" // Para Input #include "lang.h" // Para setLanguage #include "manage_hiscore_table.h" // Para ManageHiScoreTable #include "options.h" // Para loadFromFile, saveToFile, Settings, settings, setConfigFile, setControllersFile #include "param.h" // Para loadParamsFromFile #include "resource_helper.h" // Para ResourceHelper #include "player.h" // Para Player #include "resource.h" // Para Resource #include "screen.h" // Para Screen #include "section.hpp" // Para Name, Options, name, options, AttractMode, attract_mode #include "sections/credits.h" // Para Credits #include "sections/game.h" // Para Game #include "sections/hiscore_table.h" // Para HiScoreTable #include "sections/instructions.h" // Para Instructions #include "sections/intro.h" // Para Intro #include "sections/logo.h" // Para Logo #include "sections/title.h" // Para Title #include "shutdown.h" // Para resultToString, shutdownSystem, ShutdownResult #include "system_utils.h" // Para createApplicationFolder, resultToString, Result #include "ui/notifier.h" // Para Notifier #include "ui/service_menu.h" // Para ServiceMenu #include "utils.h" // Para Overrides, overrides, getPath // Constructor Director::Director(int argc, std::span argv) { #ifdef RECORDING Section::name = Section::Name::GAME; Section::options = Section::Options::GAME_PLAY_1P; #elif _DEBUG Section::name = Section::Name::GAME; Section::options = Section::Options::GAME_PLAY_1P; #else // NORMAL GAME Section::name = Section::Name::LOGO; Section::options = Section::Options::NONE; #endif Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO; // Establece el nivel de prioridad de la categoría de registro SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); SDL_SetLogPriority(SDL_LOG_CATEGORY_TEST, SDL_LOG_PRIORITY_ERROR); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Game start"); // Inicia la semilla aleatoria usando el tiempo actual en segundos std::srand(static_cast(std::time(nullptr))); // Comprueba los parametros del programa checkProgramArguments(argc, argv); // Crea la carpeta del sistema donde guardar los datos persistentes createSystemFolder("jailgames"); createSystemFolder("jailgames/coffee_crisis_arcade_edition"); init(); } Director::~Director() { close(); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nBye!"); } // Inicializa todo void Director::init() { // Configuración inicial de parametros Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos ResourceHelper::initializeResourceSystem("resources.pack"); loadAssets(); // Crea el índice de archivos Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración Options::setControllersFile(Asset::get()->get("controllers.json")); // Establece el fichero de configuración de mandos Options::loadFromFile(); // Carga el archivo de configuración loadParams(); // Carga los parámetros del programa loadScoreFile(); // Carga el archivo de puntuaciones // Inicialización de subsistemas principales Lang::setLanguage(Options::settings.language); // Carga el archivo de idioma Screen::init(); // Inicializa la pantalla y el sistema de renderizado Audio::init(); // Activa el sistema de audio #ifdef _DEBUG Resource::init(Resource::LoadingMode::PRELOAD); // Inicializa el sistema de gestión de recursos #else Resource::init(Resource::LoadingMode::PRELOAD); // Inicializa el sistema de gestión de recursos #endif ServiceMenu::init(); // Inicializa el menú de servicio Notifier::init(std::string(), Resource::get()->getText("8bithud")); // Inicialización del sistema de notificaciones Screen::get()->getSingletons(); // Obtiene los punteros al resto de singletones } // Cierra todo y libera recursos del sistema y de los singletons void Director::close() { // Guarda las opciones actuales en el archivo de configuración Options::saveToFile(); // Libera los singletons y recursos en orden inverso al de inicialización Notifier::destroy(); // Libera el sistema de notificaciones ServiceMenu::destroy(); // Libera el sistema de menú de servicio Input::destroy(); // Libera el sistema de entrada Resource::destroy(); // Libera el sistema de recursos gráficos y de texto Audio::destroy(); // Libera el sistema de audio Screen::destroy(); // Libera el sistema de pantalla y renderizado Asset::destroy(); // Libera el gestor de archivos // Libera todos los recursos de SDL SDL_Quit(); // Apaga el sistema shutdownSystem(Section::options == Section::Options::SHUTDOWN); } // Carga los parametros void Director::loadParams() { // Carga los parametros para configurar el juego #ifdef ANBERNIC const std::string PARAM_FILE_PATH = Asset::get()->get("param_320x240.txt"); #else const std::string PARAM_FILE_PATH = Asset::get()->get(Options::settings.params_file); #endif loadParamsFromFile(PARAM_FILE_PATH); } // Carga el fichero de puntuaciones void Director::loadScoreFile() { auto manager = std::make_unique(Options::settings.hi_score_table); #ifdef _DEBUG manager->clear(); #else if (overrides.clear_hi_score_table) { manager->clear(); } else { manager->loadFromFile(Asset::get()->get("score.bin")); } #endif } // Carga el indice de ficheros desde un fichero void Director::loadAssets() { #ifdef MACOS_BUNDLE const std::string PREFIX = "/../Resources"; #else const std::string PREFIX; #endif // Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración) std::string config_path = executable_path_ + PREFIX + "/config/assets.txt"; Asset::get()->loadFromFile(config_path, PREFIX, system_folder_); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully"); // Si falta algun fichero, sale del programa if (!Asset::get()->check()) { throw std::runtime_error("Falta algun fichero"); } } // Comprueba los parametros del programa void Director::checkProgramArguments(int argc, std::span argv) { // Establece la ruta del programa executable_path_ = getPath(argv[0]); // Comprueba el resto de parámetros for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if (arg == "--320x240") { overrides.param_file = arg; } else if (arg == "--clear_score") { overrides.clear_hi_score_table = true; } } } // Crea la carpeta del sistema donde guardar datos void Director::createSystemFolder(const std::string &folder) { auto result = SystemUtils::createApplicationFolder(folder, system_folder_); if (result != SystemUtils::Result::SUCCESS) { std::cerr << "Error creando carpeta del sistema: " << SystemUtils::resultToString(result) << '\n'; exit(EXIT_FAILURE); } } // Ejecuta la sección con el logo void Director::runLogo() { auto logo = std::make_unique(); logo->run(); } // Ejecuta la sección con la secuencia de introducción void Director::runIntro() { auto intro = std::make_unique(); intro->run(); } // Ejecuta la sección con el título del juego void Director::runTitle() { auto title = std::make_unique(); title->run(); } // Ejecuta la sección donde se juega al juego void Director::runGame() { Player::Id player_id = Player::Id::PLAYER1; switch (Section::options) { case Section::Options::GAME_PLAY_1P: player_id = Player::Id::PLAYER1; break; case Section::Options::GAME_PLAY_2P: player_id = Player::Id::PLAYER2; break; case Section::Options::GAME_PLAY_BOTH: player_id = Player::Id::BOTH_PLAYERS; break; default: break; } #ifdef _DEBUG constexpr int CURRENT_STAGE = 0; #else constexpr int CURRENT_STAGE = 0; #endif auto game = std::make_unique<Game>(player_id, CURRENT_STAGE, Game::DEMO_OFF); game->run(); } // Ejecuta la sección donde se muestran las instrucciones void Director::runInstructions() { auto instructions = std::make_unique<Instructions>(); instructions->run(); } // Ejecuta la sección donde se muestran los creditos del programa void Director::runCredits() { auto credits = std::make_unique<Credits>(); credits->run(); } // Ejecuta la sección donde se muestra la tabla de puntuaciones void Director::runHiScoreTable() { auto hi_score_table = std::make_unique<HiScoreTable>(); hi_score_table->run(); } // Ejecuta el juego en modo demo void Director::runDemoGame() { const auto PLAYER_ID = static_cast<Player::Id>((rand() % 2) + 1); constexpr auto CURRENT_STAGE = 0; auto game = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, Game::DEMO_ON); game->run(); } // Reinicia objetos y vuelve a la sección inicial void Director::reset() { Options::saveToFile(); Options::loadFromFile(); Lang::setLanguage(Options::settings.language); Audio::get()->stopMusic(); Audio::get()->stopAllSounds(); Resource::get()->reload(); ServiceMenu::get()->reset(); Section::name = Section::Name::LOGO; } auto Director::run() -> int { // Bucle principal while (Section::name != Section::Name::QUIT) { switch (Section::name) { case Section::Name::RESET: reset(); break; case Section::Name::LOGO: runLogo(); break; case Section::Name::INTRO: runIntro(); break; case Section::Name::TITLE: runTitle(); break; case Section::Name::GAME: runGame(); break; case Section::Name::HI_SCORE_TABLE: runHiScoreTable(); break; case Section::Name::GAME_DEMO: runDemoGame(); break; case Section::Name::INSTRUCTIONS: runInstructions(); break; case Section::Name::CREDITS: runCredits(); break; default: break; } } return 0; } // Apaga el sistema de forma segura void Director::shutdownSystem(bool should_shutdown) { if (should_shutdown) { auto result = SystemShutdown::shutdownSystem(5, true); // 5 segundos, forzar apps if (result != SystemShutdown::ShutdownResult::SUCCESS) { std::cerr << SystemShutdown::resultToString(result) << '\n'; } } }