#include "core/system/director.hpp" #include #include // Para mkdir, stat, S_IRWXU #include // Para getuid #include // Para errno, EEXIST, EACCES, ENAMETOO... #include // Para printf, perror #include // Para exit, EXIT_FAILURE, srand #include // Para basic_ostream, operator<<, cout #include // Para make_unique, unique_ptr #include // Para operator+, allocator, char_traits #include "core/audio/audio.hpp" // Para Audio #include "core/input/input.hpp" // Para Input, InputAction #include "core/rendering/screen.hpp" // Para Screen #include "core/resources/asset.hpp" // Para Asset, AssetType #include "core/resources/resource.hpp" // Para Resource #include "core/system/debug.hpp" // Para Debug #include "game/gameplay/cheevos.hpp" // Para Cheevos #include "game/options.hpp" // Para Options, options, OptionsVideo #include "game/scene_manager.hpp" // Para SceneManager #include "game/scenes/credits.hpp" // Para Credits #include "game/scenes/ending.hpp" // Para Ending #include "game/scenes/ending2.hpp" // Para Ending2 #include "game/scenes/game.hpp" // Para Game, GameMode #include "game/scenes/game_over.hpp" // Para GameOver #include "game/scenes/loading_screen.hpp" // Para LoadingScreen #include "game/scenes/logo.hpp" // Para Logo #include "game/scenes/title.hpp" // Para Title #include "game/ui/notifier.hpp" // Para Notifier #include "utils/defines.hpp" // Para WINDOW_CAPTION #ifndef _WIN32 #include #endif // Constructor Director::Director(std::vector const& args) { std::cout << "Game start" << '\n'; // Crea e inicializa las opciones del programa Options::init(); // Comprueba los parametros del programa executable_path_ = getPath(checkProgramArguments(args)); // Crea el objeto que controla los ficheros de recursos Asset::init(executable_path_); // Crea la carpeta del sistema donde guardar datos createSystemFolder("jailgames"); createSystemFolder("jailgames/jaildoctors_dilemma"); // Si falta algún fichero no inicia el programa if (!setFileList()) { exit(EXIT_FAILURE); } // Carga las opciones desde un fichero Options::loadFromFile(Asset::get()->get("config.txt")); // Inicializa JailAudio Audio::init(); // Crea los objetos Screen::init(); SDL_HideCursor(); Resource::init(); Notifier::init("", "8bithud"); Screen::get()->setNotificationsEnabled(true); Input::init(Asset::get()->get("gamecontrollerdb.txt")); initInput(); Debug::init(); Cheevos::init(Asset::get()->get("cheevos.bin")); } Director::~Director() { // Guarda las opciones a un fichero Options::saveToFile(Asset::get()->get("config.txt")); // Destruye los singletones Cheevos::destroy(); Debug::destroy(); Input::destroy(); Notifier::destroy(); Resource::destroy(); Audio::destroy(); Screen::destroy(); Asset::destroy(); SDL_Quit(); std::cout << "\nBye!" << '\n'; } // Comprueba los parametros del programa auto Director::checkProgramArguments(std::vector const& args) -> std::string { // Iterar sobre los argumentos del programa (saltando args[0] que es el ejecutable) for (std::size_t i = 1; i < args.size(); ++i) { const std::string& argument = args[i]; if (argument == "--console") { Options::console = true; } else if (argument == "--infiniteLives") { Options::cheats.infinite_lives = Options::Cheat::State::ENABLED; } else if (argument == "--invincible") { Options::cheats.invincible = Options::Cheat::State::ENABLED; } else if (argument == "--jailEnabled") { Options::cheats.jail_is_open = Options::Cheat::State::ENABLED; } else if (argument == "--altSkin") { Options::cheats.alternate_skin = Options::Cheat::State::ENABLED; } } return args[0]; } // 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 = {.st_dev = 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); } } } } // Inicia las variables necesarias para arrancar el programa void Director::initInput() { // Busca si hay un mando conectado Input::get()->discoverGameControllers(); // Teclado - Movimiento if (Options::keys == Options::ControlScheme::CURSOR) { Input::get()->bindKey(InputAction::JUMP, SDL_SCANCODE_UP); Input::get()->bindKey(InputAction::LEFT, SDL_SCANCODE_LEFT); Input::get()->bindKey(InputAction::RIGHT, SDL_SCANCODE_RIGHT); Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_UP); Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_DOWN); } else if (Options::keys == Options::ControlScheme::OPQA) { Input::get()->bindKey(InputAction::JUMP, SDL_SCANCODE_Q); Input::get()->bindKey(InputAction::LEFT, SDL_SCANCODE_O); Input::get()->bindKey(InputAction::RIGHT, SDL_SCANCODE_P); Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_Q); Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_A); } else if (Options::keys == Options::ControlScheme::WASD) { Input::get()->bindKey(InputAction::JUMP, SDL_SCANCODE_W); Input::get()->bindKey(InputAction::LEFT, SDL_SCANCODE_A); Input::get()->bindKey(InputAction::RIGHT, SDL_SCANCODE_D); Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_W); Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_S); } // Teclado - Otros Input::get()->bindKey(InputAction::ACCEPT, SDL_SCANCODE_RETURN); Input::get()->bindKey(InputAction::CANCEL, SDL_SCANCODE_ESCAPE); Input::get()->bindKey(InputAction::PAUSE, SDL_SCANCODE_H); Input::get()->bindKey(InputAction::EXIT, SDL_SCANCODE_ESCAPE); Input::get()->bindKey(InputAction::WINDOW_DEC_ZOOM, SDL_SCANCODE_F1); Input::get()->bindKey(InputAction::WINDOW_INC_ZOOM, SDL_SCANCODE_F2); Input::get()->bindKey(InputAction::TOGGLE_VIDEOMODE, SDL_SCANCODE_F3); Input::get()->bindKey(InputAction::TOGGLE_SHADERS, SDL_SCANCODE_F4); Input::get()->bindKey(InputAction::NEXT_PALETTE, SDL_SCANCODE_F5); Input::get()->bindKey(InputAction::PREVIOUS_PALETTE, SDL_SCANCODE_F6); Input::get()->bindKey(InputAction::TOGGLE_INTEGER_SCALE, SDL_SCANCODE_F7); Input::get()->bindKey(InputAction::SHOW_DEBUG_INFO, SDL_SCANCODE_F12); Input::get()->bindKey(InputAction::TOGGLE_MUSIC, SDL_SCANCODE_M); Input::get()->bindKey(InputAction::TOGGLE_BORDER, SDL_SCANCODE_B); // MANDO const int NUM_GAMEPADS = Input::get()->getNumControllers(); for (int i = 0; i < NUM_GAMEPADS; ++i) { // Movimiento Input::get()->bindGameControllerButton(i, InputAction::JUMP, SDL_GAMEPAD_BUTTON_SOUTH); Input::get()->bindGameControllerButton(i, InputAction::LEFT, SDL_GAMEPAD_BUTTON_DPAD_LEFT); Input::get()->bindGameControllerButton(i, InputAction::RIGHT, SDL_GAMEPAD_BUTTON_DPAD_RIGHT); // Otros Input::get()->bindGameControllerButton(i, InputAction::ACCEPT, SDL_GAMEPAD_BUTTON_SOUTH); Input::get()->bindGameControllerButton(i, InputAction::CANCEL, SDL_GAMEPAD_BUTTON_EAST); #ifdef GAME_CONSOLE Input::get()->bindGameControllerButton(i, InputAction::input_pause, SDL_GAMEPAD_BUTTON_BACK); Input::get()->bindGameControllerButton(i, InputAction::input_exit, SDL_GAMEPAD_BUTTON_START); #else Input::get()->bindGameControllerButton(i, InputAction::PAUSE, SDL_GAMEPAD_BUTTON_START); Input::get()->bindGameControllerButton(i, InputAction::EXIT, SDL_GAMEPAD_BUTTON_BACK); #endif Input::get()->bindGameControllerButton(i, InputAction::NEXT_PALETTE, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER); Input::get()->bindGameControllerButton(i, InputAction::TOGGLE_MUSIC, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER); Input::get()->bindGameControllerButton(i, InputAction::TOGGLE_BORDER, SDL_GAMEPAD_BUTTON_NORTH); } } // Crea el indice de ficheros auto Director::setFileList() -> bool { // Determinar el prefijo de ruta según la plataforma #ifdef MACOS_BUNDLE const std::string PREFIX = "/../Resources"; #else const std::string PREFIX; #endif // Construir ruta al archivo de configuración de assets std::string config_path = executable_path_ + PREFIX + "/config/assets.txt"; // Cargar todos los assets desde el archivo de configuración Asset::get()->loadFromFile(config_path, PREFIX, system_folder_); // Verificar que todos los assets requeridos existen return Asset::get()->check(); } // Ejecuta la seccion de juego con el logo void Director::runLogo() { auto logo = std::make_unique(); logo->run(); } // Ejecuta la seccion de juego de la pantalla de carga void Director::runLoadingScreen() { auto loading_screen = std::make_unique(); loading_screen->run(); } // Ejecuta la seccion de juego con el titulo y los menus void Director::runTitle() { auto title = std::make_unique(); title->run(); } // Ejecuta la seccion de los creditos del juego void Director::runCredits() { auto credits = std::make_unique<Credits>(); credits->run(); } // Ejecuta la seccion de la demo, donde se ven pantallas del juego void Director::runDemo() { auto game = std::make_unique<Game>(Game::Mode::DEMO); game->run(); } // Ejecuta la seccion del final del juego void Director::runEnding() { auto ending = std::make_unique<Ending>(); ending->run(); } // Ejecuta la seccion del final del juego void Director::runEnding2() { auto ending2 = std::make_unique<Ending2>(); ending2->run(); } // Ejecuta la seccion del final de la partida void Director::runGameOver() { auto game_over = std::make_unique<GameOver>(); game_over->run(); } // Ejecuta la seccion de juego donde se juega void Director::runGame() { Audio::get()->stopMusic(); auto game = std::make_unique<Game>(Game::Mode::GAME); game->run(); } auto Director::run() -> int { // Bucle principal while (SceneManager::current != SceneManager::Scene::QUIT) { switch (SceneManager::current) { case SceneManager::Scene::LOGO: runLogo(); break; case SceneManager::Scene::LOADING_SCREEN: runLoadingScreen(); break; case SceneManager::Scene::TITLE: runTitle(); break; case SceneManager::Scene::CREDITS: runCredits(); break; case SceneManager::Scene::DEMO: runDemo(); break; case SceneManager::Scene::GAME: runGame(); break; case SceneManager::Scene::GAME_OVER: runGameOver(); break; case SceneManager::Scene::ENDING: runEnding(); break; case SceneManager::Scene::ENDING2: runEnding2(); break; default: break; } } return 0; }