// IWYU pragma: no_include #include "director.h" #include // Para SDL_Scancode, SDL_GamepadButton, SDL_LogCategory, SDL_LogInfo, SDL_SetLogPriority, SDL_LogPriority, SDL_Quit #include // Para mkdir, stat, S_IRWXU #include // Para getuid #include // Para min #include // Para errno, EEXIST, EACCES, ENAMETOOLONG #include // Para printf, perror #include // Para exit, EXIT_FAILURE, size_t, srand, rand, system #include // Para time #include // Para make_unique, unique_ptr #include // Para span #include // Para runtime_error #include // Para operator+, allocator, char_traits, operator==, string, basic_string #include // Para vector #include "asset.h" // Para Asset, AssetType #include "audio.h" // Para Audio #include "input.h" // Para Input, InputAction #include "lang.h" // Para setLanguage #include "manage_hiscore_table.h" // Para ManageHiScoreTable #include "options.h" // Para GamepadOptions, controllers, loadFromFile, saveToFile, SettingsOptions, settings, getPlayerWhoUsesKeyboard, setKeyboardToPlayer #include "param.h" // Para loadParamsFromFile #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, GAME_MODE_DEMO_OFF, GAME_MODE_DEMO_ON #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 "ui/notifier.h" // Para Notifier #include "ui/service_menu.h" // Para ServiceMenu #include "utils.h" // Para Overrides, overrides, getPath #ifndef _WIN32 #include // Para getpwuid, passwd #endif // 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 setFileList(); // 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 Resource::init(); // Inicializa el sistema de gestión de recursos //bindInputs(); // Asigna los controles a la entrada del sistema 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 paramFilePath = asset->get("param_320x240.txt"); #else const std::string PARAM_FILE_PATH = overrides.param_file == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt"); #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 } // Asigna los botones y teclas al objeto Input void Director::bindInputs() { /*static auto input = Input::get(); // Teclado - Movimiento del jugador input->bindKey(Input::Action::UP, SDL_SCANCODE_UP); input->bindKey(Input::Action::DOWN, SDL_SCANCODE_DOWN); input->bindKey(Input::Action::LEFT, SDL_SCANCODE_LEFT); input->bindKey(Input::Action::RIGHT, SDL_SCANCODE_RIGHT); // Teclado - Disparo del jugador input->bindKey(Input::Action::FIRE_LEFT, SDL_SCANCODE_Q); input->bindKey(Input::Action::FIRE_CENTER, SDL_SCANCODE_W); input->bindKey(Input::Action::FIRE_RIGHT, SDL_SCANCODE_E); // Teclado - Interfaz input->bindKey(Input::Action::START, SDL_SCANCODE_RETURN); // Teclado - Menu de servicio input->bindKey(Input::Action::SERVICE, SDL_SCANCODE_0); input->bindKey(Input::Action::SM_SELECT, SDL_SCANCODE_RETURN); input->bindKey(Input::Action::SM_BACK, SDL_SCANCODE_BACKSPACE); // Teclado - Control del programa input->bindKey(Input::Action::EXIT, SDL_SCANCODE_ESCAPE); input->bindKey(Input::Action::PAUSE, SDL_SCANCODE_P); input->bindKey(Input::Action::BACK, SDL_SCANCODE_BACKSPACE); input->bindKey(Input::Action::WINDOW_DEC_SIZE, SDL_SCANCODE_F1); input->bindKey(Input::Action::WINDOW_INC_SIZE, SDL_SCANCODE_F2); input->bindKey(Input::Action::WINDOW_FULLSCREEN, SDL_SCANCODE_F3); input->bindKey(Input::Action::TOGGLE_VIDEO_SHADERS, SDL_SCANCODE_F4); input->bindKey(Input::Action::TOGGLE_VIDEO_INTEGER_SCALE, SDL_SCANCODE_F5); input->bindKey(Input::Action::TOGGLE_VIDEO_VSYNC, SDL_SCANCODE_F6); input->bindKey(Input::Action::TOGGLE_AUDIO, SDL_SCANCODE_F7); input->bindKey(Input::Action::TOGGLE_AUTO_FIRE, SDL_SCANCODE_F8); input->bindKey(Input::Action::CHANGE_LANG, SDL_SCANCODE_F9); input->bindKey(Input::Action::RESET, SDL_SCANCODE_F10); input->bindKey(Input::Action::SHOW_INFO, SDL_SCANCODE_F12); // Asigna botones a inputs auto gamepads = input->getGamepads(); for (auto &gamepad : gamepads) { // Mando - Movimiento del jugador input->bindGameControllerButton(gamepad, Input::Action::UP, SDL_GAMEPAD_BUTTON_DPAD_UP); input->bindGameControllerButton(gamepad, Input::Action::DOWN, SDL_GAMEPAD_BUTTON_DPAD_DOWN); input->bindGameControllerButton(gamepad, Input::Action::LEFT, SDL_GAMEPAD_BUTTON_DPAD_LEFT); input->bindGameControllerButton(gamepad, Input::Action::RIGHT, SDL_GAMEPAD_BUTTON_DPAD_RIGHT); // Mando - Disparo del jugador input->bindGameControllerButton(gamepad, Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_WEST); input->bindGameControllerButton(gamepad, Input::Action::FIRE_CENTER, SDL_GAMEPAD_BUTTON_NORTH); input->bindGameControllerButton(gamepad, Input::Action::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_EAST); // Mando - Interfaz input->bindGameControllerButton(gamepad, Input::Action::START, SDL_GAMEPAD_BUTTON_START); input->bindGameControllerButton(gamepad, Input::Action::SERVICE, SDL_GAMEPAD_BUTTON_BACK); } // Mapea las asignaciones a los botones desde el archivo de configuración, si se da el caso const size_t MAX_CONTROLLERS = std::min(2, NUM_GAMEPADS); for (size_t i = 0; i < MAX_CONTROLLERS; ++i) { for (auto &controller : Options::controllers) { if (input->getControllerName(i) == controller.name) { for (size_t j = 0; j < controller.inputs.size(); ++j) { input->bindGameControllerButton(i, controller.inputs.at(j), controller.buttons.at(j)); } } } } // Asigna botones a inputs desde otros inputs for (auto &gamepad : gamepads) { // Mando - Menu de servicio input->bindGameControllerButton(gamepad, Input::Action::SM_SELECT, Input::Action::FIRE_LEFT); input->bindGameControllerButton(gamepad, Input::Action::SM_BACK, Input::Action::FIRE_CENTER); } // Guarda las asignaciones de botones en las opciones de los dos primeros mandos for (size_t i = 0; i < MAX_CONTROLLERS; ++i) { // Variables asociadas al mando Options::controllers.at(i).index = i; Options::controllers.at(i).name = input->getControllerName(i); Options::controllers.at(i).plugged = true; // Asignaciones de botones for (size_t j = 0; j < Options::controllers.at(i).inputs.size(); ++j) { Options::controllers.at(i).buttons.at(j) = input->getControllerBinding(i, Options::controllers.at(i).inputs.at(j)); } } // Asegura que algún jugador tenga el teclado asignado if (Options::getPlayerWhoUsesKeyboard() == 0) { Options::setKeyboardToPlayer(1); }*/ } // Crea el indice de ficheros void Director::setFileList() { #ifdef MACOS_BUNDLE const std::string prefix = "/../Resources"; #else const std::string PREFIX; #endif // Ficheros de configuración Asset::get()->add(system_folder_ + "/config.txt", AssetType::DATA, false, true); Asset::get()->add(system_folder_ + "/controllers.json", AssetType::DATA, false, true); Asset::get()->add(system_folder_ + "/score.bin", AssetType::DATA, false, true); Asset::get()->add(PREFIX + "/data/config/param_320x240.txt", AssetType::DATA); Asset::get()->add(PREFIX + "/data/config/param_320x256.txt", AssetType::DATA); Asset::get()->add(PREFIX + "/data/config/demo1.bin", AssetType::DEMODATA); Asset::get()->add(PREFIX + "/data/config/demo2.bin", AssetType::DEMODATA); Asset::get()->add(PREFIX + "/data/config/gamecontrollerdb.txt", AssetType::DATA); Asset::get()->add(PREFIX + "/data/config/formations.txt", AssetType::DATA); Asset::get()->add(PREFIX + "/data/config/pools.txt", AssetType::DATA); // Musicas Asset::get()->add(PREFIX + "/data/music/intro.ogg", AssetType::MUSIC); Asset::get()->add(PREFIX + "/data/music/playing.ogg", AssetType::MUSIC); Asset::get()->add(PREFIX + "/data/music/title.ogg", AssetType::MUSIC); Asset::get()->add(PREFIX + "/data/music/credits.ogg", AssetType::MUSIC); // Sonidos Asset::get()->add(PREFIX + "/data/sound/balloon_pop0.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_pop1.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_pop2.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_pop3.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_bounce0.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_bounce1.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_bounce2.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/balloon_bounce3.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/bullet.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/clock.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/coffee_out.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/continue_clock.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/debian_drop.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/debian_pickup.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/hi_score_achieved.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/item_drop.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/item_pickup.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/jump.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/logo.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/notify.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/player_collision.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/power_ball_explosion.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/service_menu_adjust.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/service_menu_move.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/service_menu_select.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/stage_change.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/tabe_hit.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/tabe.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/title.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/voice_aw_aw_aw.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/voice_coffee.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/voice_get_ready.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/voice_no.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/voice_power_up.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/voice_thankyou.wav", AssetType::SOUND); Asset::get()->add(PREFIX + "/data/sound/walk.wav", AssetType::SOUND); // Shaders Asset::get()->add(PREFIX + "/data/shaders/crtpi_256.glsl", AssetType::DATA); Asset::get()->add(PREFIX + "/data/shaders/crtpi_240.glsl", AssetType::DATA); // Texturas - Balloons Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon0.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon0.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon1.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon1.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon2.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon2.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon3.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/balloon3.ani", AssetType::ANIMATION); // Texturas - Explosiones Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion0.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion0.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion1.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion1.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion2.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion2.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion3.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/explosion3.ani", AssetType::ANIMATION); // Texturas - Power Ball Asset::get()->add(PREFIX + "/data/gfx/balloon/powerball.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/balloon/powerball.ani", AssetType::ANIMATION); // Texturas - Bala Asset::get()->add(PREFIX + "/data/gfx/bullet/bullet.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/bullet/bullet.ani", AssetType::ANIMATION); // Texturas - Tabe Asset::get()->add(PREFIX + "/data/gfx/tabe/tabe.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/tabe/tabe.ani", AssetType::ANIMATION); // Texturas - Juego Asset::get()->add(PREFIX + "/data/gfx/game/game_buildings.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_clouds2.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_grass.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_power_meter.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_sky_colors.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_sun.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/game/game_moon.png", AssetType::BITMAP); // Texturas - Intro Asset::get()->add(PREFIX + "/data/gfx/intro/intro1.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/intro/intro2.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/intro/intro3.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/intro/intro4.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/intro/intro5.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/intro/intro6.png", AssetType::BITMAP); // Texturas - Logo Asset::get()->add(PREFIX + "/data/gfx/logo/logo_jailgames.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/logo/logo_jailgames_mini.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/logo/logo_since_1998.png", AssetType::BITMAP); // Texturas - Items Asset::get()->add(PREFIX + "/data/gfx/item/item_points1_disk.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_points1_disk.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/item/item_points2_gavina.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_points2_gavina.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/item/item_points3_pacmar.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_points3_pacmar.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/item/item_clock.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_clock.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/item/item_coffee.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_coffee.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/item/item_debian.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_debian.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/item/item_coffee_machine.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION); // Texturas - Titulo Asset::get()->add(PREFIX + "/data/gfx/title/title_bg_tile.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/title/title_coffee.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/title/title_crisis.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/title/title_arcade_edition.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/title/title_dust.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/title/title_dust.ani", AssetType::ANIMATION); // Texturas - Jugador 1 Asset::get()->add(PREFIX + "/data/gfx/player/player1.gif", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/player/player1_coffee1.pal", AssetType::PALETTE); Asset::get()->add(PREFIX + "/data/gfx/player/player1_coffee2.pal", AssetType::PALETTE); Asset::get()->add(PREFIX + "/data/gfx/player/player1_invencible.pal", AssetType::PALETTE); Asset::get()->add(PREFIX + "/data/gfx/player/player1_power.png", AssetType::BITMAP); // Texturas - Jugador 2 Asset::get()->add(PREFIX + "/data/gfx/player/player2.gif", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/gfx/player/player2_coffee1.pal", AssetType::PALETTE); Asset::get()->add(PREFIX + "/data/gfx/player/player2_coffee2.pal", AssetType::PALETTE); Asset::get()->add(PREFIX + "/data/gfx/player/player2_invencible.pal", AssetType::PALETTE); Asset::get()->add(PREFIX + "/data/gfx/player/player2_power.png", AssetType::BITMAP); // Animaciones del jugador Asset::get()->add(PREFIX + "/data/gfx/player/player.ani", AssetType::ANIMATION); Asset::get()->add(PREFIX + "/data/gfx/player/player_power.ani", AssetType::ANIMATION); // Texturas - Golpe del jugador Asset::get()->add(PREFIX + "/data/gfx/player/hit.png", AssetType::BITMAP); // Fuentes de texto Asset::get()->add(PREFIX + "/data/font/8bithud.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/8bithud.txt", AssetType::FONT); Asset::get()->add(PREFIX + "/data/font/aseprite.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/aseprite.txt", AssetType::FONT); Asset::get()->add(PREFIX + "/data/font/smb2.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/smb2_grad.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/smb2.txt", AssetType::FONT); Asset::get()->add(PREFIX + "/data/font/04b_25.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25.txt", AssetType::FONT); Asset::get()->add(PREFIX + "/data/font/04b_25_2x.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25_2x.txt", AssetType::FONT); Asset::get()->add(PREFIX + "/data/font/04b_25_metal.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25_grey.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25_flat.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25_reversed.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25_flat_2x.png", AssetType::BITMAP); Asset::get()->add(PREFIX + "/data/font/04b_25_reversed_2x.png", AssetType::BITMAP); // Textos Asset::get()->add(PREFIX + "/data/lang/es_ES.json", AssetType::LANG); Asset::get()->add(PREFIX + "/data/lang/en_UK.json", AssetType::LANG); Asset::get()->add(PREFIX + "/data/lang/ba_BA.json", AssetType::LANG); // 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) { #ifdef _WIN32 system_folder_ = std::string(getenv("APPDATA")) + "/" + folder; #elif __APPLE__ struct passwd *pw = getpwuid(getuid()); const char *homedir = pw->pw_dir; system_folder_ = std::string(homedir) + "/Library/Application Support" + "/" + folder; #elif __linux__ struct passwd *pw = getpwuid(getuid()); const char *homedir = pw->pw_dir; system_folder_ = std::string(homedir) + "/.config/" + folder; { // Intenta crear ".config", per si no existeix std::string config_base_folder = std::string(homedir) + "/.config"; int ret = mkdir(config_base_folder.c_str(), S_IRWXU); if (ret == -1 && errno != EEXIST) { printf("ERROR CREATING CONFIG BASE FOLDER."); exit(EXIT_FAILURE); } } #endif struct stat st = {0}; if (stat(system_folder_.c_str(), &st) == -1) { errno = 0; #ifdef _WIN32 int ret = mkdir(system_folder_.c_str()); #else int ret = mkdir(system_folder_.c_str(), S_IRWXU); #endif if (ret == -1) { switch (errno) { case EACCES: printf("the parent directory does not allow write"); exit(EXIT_FAILURE); case EEXIST: printf("pathname already exists"); exit(EXIT_FAILURE); case ENAMETOOLONG: printf("pathname is too long"); exit(EXIT_FAILURE); default: perror("mkdir"); 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(); } // Input::get()->discoverGameControllers(); bindInputs(); 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 void Director::shutdownSystem(bool should_shutdown) { if (should_shutdown) { #ifdef _WIN32 // Apaga el sistema en Windows system("shutdown /s /t 5"); #elif __APPLE__ // Apaga el sistema en macOS system("sudo shutdown -h +0.1"); #elif __linux__ // Apaga el sistema en Linux system("sleep 5; shutdown -h now"); #else // Sistema operativo no compatible #error "Sistema operativo no soportado" #endif } }