#include "common/jscore.h" #include "common/utils.h" #include "const.h" #include "director.h" #include #include #include // Constructor Director::Director(std::string path) { // Inicializa variables section.name = PROG_SECTION_LOGO; // Crea el objeto que controla los ficheros de recursos asset = new Asset(path); // Establece la lista de ficheros if (!setFileList()) { // Si falta algún fichero no inicia el programa section.name = PROG_SECTION_QUIT; } // Inicializa las opciones del programa initOptions(); // Carga el fichero de configuración loadConfigFile(); // Inicializa SDL initSDL(); // Inicializa JailAudio initJailAudio(); // Crea los objetos lang = new Lang(asset); lang->setLang(options->language); input = new Input(asset->get("controllerdb.txt")); initInput(); screen = new Screen(window, renderer, asset, options, GAME_WIDTH, GAME_HEIGHT); // Inicializa los servicios online initOnline(); } Director::~Director() { saveConfigFile(); delete asset; delete input; delete screen; delete lang; delete options; SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } // Inicializa el objeto input void Director::initInput() { // Teclado input->bindKey(INPUT_UP, SDL_SCANCODE_UP); input->bindKey(INPUT_DOWN, SDL_SCANCODE_DOWN); input->bindKey(INPUT_LEFT, SDL_SCANCODE_LEFT); input->bindKey(INPUT_RIGHT, SDL_SCANCODE_RIGHT); input->bindKey(INPUT_ACCEPT, SDL_SCANCODE_RETURN); input->bindKey(INPUT_CANCEL, SDL_SCANCODE_ESCAPE); input->bindKey(INPUT_BUTTON_1, SDL_SCANCODE_Q); input->bindKey(INPUT_BUTTON_2, SDL_SCANCODE_W); input->bindKey(INPUT_BUTTON_3, SDL_SCANCODE_E); input->bindKey(INPUT_BUTTON_PAUSE, SDL_SCANCODE_ESCAPE); // PAUSE input->bindKey(INPUT_BUTTON_ESCAPE, SDL_SCANCODE_ESCAPE); // ESCAPE // Mando input->bindGameControllerButton(INPUT_UP, SDL_CONTROLLER_BUTTON_DPAD_UP); input->bindGameControllerButton(INPUT_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN); input->bindGameControllerButton(INPUT_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT); input->bindGameControllerButton(INPUT_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); input->bindGameControllerButton(INPUT_ACCEPT, SDL_CONTROLLER_BUTTON_B); input->bindGameControllerButton(INPUT_CANCEL, SDL_CONTROLLER_BUTTON_A); input->bindGameControllerButton(INPUT_BUTTON_1, SDL_CONTROLLER_BUTTON_X); input->bindGameControllerButton(INPUT_BUTTON_2, SDL_CONTROLLER_BUTTON_Y); input->bindGameControllerButton(INPUT_BUTTON_3, SDL_CONTROLLER_BUTTON_B); input->bindGameControllerButton(INPUT_BUTTON_PAUSE, SDL_CONTROLLER_BUTTON_GUIDE); // PAUSE input->bindGameControllerButton(INPUT_BUTTON_ESCAPE, SDL_CONTROLLER_BUTTON_GUIDE); // ESCAPE } // Inicializa JailAudio void Director::initJailAudio() { JA_Init(48000, AUDIO_S16, 2); } // Arranca SDL y crea la ventana bool Director::initSDL() { // Indicador de éxito bool success = true; // Inicializa SDL if (SDL_Init(SDL_INIT_EVERYTHING) < 0) // if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) { printf("SDL could not initialize!\nSDL Error: %s\n", SDL_GetError()); success = false; } else { // Inicia el generador de numeros aleatorios std::srand(static_cast(SDL_GetTicks())); // Establece el filtro de la textura if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(options->filter).c_str())) { printf("Warning: Nearest texture filtering not enabled!\n"); } // Crea la ventana window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, options->screenWidth * options->windowSize, options->screenHeight * options->windowSize, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); if (window == nullptr) { printf("Window could not be created!\nSDL Error: %s\n", SDL_GetError()); success = false; } else { // Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones if (options->vSync) { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); } else { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); } if (renderer == nullptr) { printf("Renderer could not be created!\nSDL Error: %s\n", SDL_GetError()); success = false; } else { // Inicializa el color de renderizado SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); // Establece el tamaño del buffer de renderizado SDL_RenderSetLogicalSize(renderer, options->screenWidth, options->screenHeight); // Establece el modo de mezcla SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); } } } printf("\n"); return success; } // Crea el indice de ficheros bool Director::setFileList() { #ifdef MACOS_BUNDLE const std::string prefix = "/../Resources"; #else const std::string prefix = ""; #endif // Ficheros de configuración asset->add(prefix + "/data/config/score.bin", t_data, false); asset->add(prefix + "/data/config/demo.bin", t_data); asset->add(prefix + "/data/config/config.bin", t_data, false); asset->add(prefix + "/data/config/config.txt", t_data, false); asset->add(prefix + "/data/config/jailer_id.txt", t_data, false); asset->add(prefix + "/data/config/gamecontrollerdb.txt", t_data); // Musicas asset->add(prefix + "/data/music/intro.ogg", t_music); asset->add(prefix + "/data/music/playing.ogg", t_music); asset->add(prefix + "/data/music/title.ogg", t_music); // Sonidos asset->add(prefix + "/data/sound/balloon.wav", t_sound); asset->add(prefix + "/data/sound/bubble1.wav", t_sound); asset->add(prefix + "/data/sound/bubble2.wav", t_sound); asset->add(prefix + "/data/sound/bubble3.wav", t_sound); asset->add(prefix + "/data/sound/bubble4.wav", t_sound); asset->add(prefix + "/data/sound/bullet.wav", t_sound); asset->add(prefix + "/data/sound/coffeeout.wav", t_sound); asset->add(prefix + "/data/sound/hiscore.wav", t_sound); asset->add(prefix + "/data/sound/itemdrop.wav", t_sound); asset->add(prefix + "/data/sound/itempickup.wav", t_sound); asset->add(prefix + "/data/sound/menu_move.wav", t_sound); asset->add(prefix + "/data/sound/menu_select.wav", t_sound); asset->add(prefix + "/data/sound/player_collision.wav", t_sound); asset->add(prefix + "/data/sound/stage_change.wav", t_sound); asset->add(prefix + "/data/sound/title.wav", t_sound); asset->add(prefix + "/data/sound/clock.wav", t_sound); asset->add(prefix + "/data/sound/powerball.wav", t_sound); // Texturas asset->add(prefix + "/data/gfx/balloon1.png", t_bitmap); asset->add(prefix + "/data/gfx/balloon1.ani", t_data); asset->add(prefix + "/data/gfx/balloon2.png", t_bitmap); asset->add(prefix + "/data/gfx/balloon2.ani", t_data); asset->add(prefix + "/data/gfx/balloon3.png", t_bitmap); asset->add(prefix + "/data/gfx/balloon3.ani", t_data); asset->add(prefix + "/data/gfx/balloon4.png", t_bitmap); asset->add(prefix + "/data/gfx/balloon4.ani", t_data); asset->add(prefix + "/data/gfx/bullet.png", t_bitmap); asset->add(prefix + "/data/gfx/game_buildings.png", t_bitmap); asset->add(prefix + "/data/gfx/game_clouds.png", t_bitmap); asset->add(prefix + "/data/gfx/game_grass.png", t_bitmap); asset->add(prefix + "/data/gfx/game_power_meter.png", t_bitmap); asset->add(prefix + "/data/gfx/game_sky_colors.png", t_bitmap); asset->add(prefix + "/data/gfx/game_text.png", t_bitmap); asset->add(prefix + "/data/gfx/intro.png", t_bitmap); asset->add(prefix + "/data/gfx/logo.png", t_bitmap); asset->add(prefix + "/data/gfx/menu_game_over.png", t_bitmap); asset->add(prefix + "/data/gfx/menu_game_over_end.png", t_bitmap); asset->add(prefix + "/data/gfx/item_points1_disk.png", t_bitmap); asset->add(prefix + "/data/gfx/item_points1_disk.ani", t_data); asset->add(prefix + "/data/gfx/item_points2_gavina.png", t_bitmap); asset->add(prefix + "/data/gfx/item_points2_gavina.ani", t_data); asset->add(prefix + "/data/gfx/item_points3_pacmar.png", t_bitmap); asset->add(prefix + "/data/gfx/item_points3_pacmar.ani", t_data); asset->add(prefix + "/data/gfx/item_clock.png", t_bitmap); asset->add(prefix + "/data/gfx/item_clock.ani", t_data); asset->add(prefix + "/data/gfx/item_coffee.png", t_bitmap); asset->add(prefix + "/data/gfx/item_coffee.ani", t_data); asset->add(prefix + "/data/gfx/item_coffee_machine.png", t_bitmap); asset->add(prefix + "/data/gfx/item_coffee_machine.ani", t_data); asset->add(prefix + "/data/gfx/title_bg_tile.png", t_bitmap); asset->add(prefix + "/data/gfx/title_coffee.png", t_bitmap); asset->add(prefix + "/data/gfx/title_crisis.png", t_bitmap); asset->add(prefix + "/data/gfx/title_dust.png", t_bitmap); asset->add(prefix + "/data/gfx/title_dust.ani", t_data); asset->add(prefix + "/data/gfx/title_gradient.png", t_bitmap); asset->add(prefix + "/data/gfx/player_head.ani", t_data); asset->add(prefix + "/data/gfx/player_body.ani", t_data); asset->add(prefix + "/data/gfx/player_legs.ani", t_data); asset->add(prefix + "/data/gfx/player_death.ani", t_data); asset->add(prefix + "/data/gfx/player_fire.ani", t_data); asset->add(prefix + "/data/gfx/player_bal1_head.png", t_bitmap); asset->add(prefix + "/data/gfx/player_bal1_body.png", t_bitmap); asset->add(prefix + "/data/gfx/player_bal1_legs.png", t_bitmap); asset->add(prefix + "/data/gfx/player_bal1_death.png", t_bitmap); asset->add(prefix + "/data/gfx/player_bal1_fire.png", t_bitmap); asset->add(prefix + "/data/gfx/player_arounder_head.png", t_bitmap); asset->add(prefix + "/data/gfx/player_arounder_body.png", t_bitmap); asset->add(prefix + "/data/gfx/player_arounder_legs.png", t_bitmap); asset->add(prefix + "/data/gfx/player_arounder_death.png", t_bitmap); asset->add(prefix + "/data/gfx/player_arounder_fire.png", t_bitmap); // Fuentes asset->add(prefix + "/data/font/8bithud.png", t_font); asset->add(prefix + "/data/font/8bithud.txt", t_font); asset->add(prefix + "/data/font/nokia.png", t_font); asset->add(prefix + "/data/font/nokia_big2.png", t_font); asset->add(prefix + "/data/font/nokia.txt", t_font); asset->add(prefix + "/data/font/nokia2.png", t_font); asset->add(prefix + "/data/font/nokia2.txt", t_font); asset->add(prefix + "/data/font/nokia_big2.txt", t_font); asset->add(prefix + "/data/font/smb2_big.png", t_font); asset->add(prefix + "/data/font/smb2_big.txt", t_font); asset->add(prefix + "/data/font/smb2.png", t_font); asset->add(prefix + "/data/font/smb2.txt", t_font); // Textos asset->add(prefix + "/data/lang/es_ES.txt", t_lang); asset->add(prefix + "/data/lang/en_UK.txt", t_lang); asset->add(prefix + "/data/lang/ba_BA.txt", t_lang); // Menus asset->add(prefix + "/data/menu/title.men", t_data); asset->add(prefix + "/data/menu/options.men", t_data); asset->add(prefix + "/data/menu/pause.men", t_data); asset->add(prefix + "/data/menu/gameover.men", t_data); asset->add(prefix + "/data/menu/player_select.men", t_data); return asset->check(); } // Inicializa las opciones del programa void Director::initOptions() { options = new options_t; // Pone unos valores por defecto options->input.clear(); input_t inp; inp.id = 0; inp.name = "KEYBOARD"; inp.deviceType = INPUT_USE_KEYBOARD; options->input.push_back(inp); inp.id = 0; inp.name = "GAME CONTROLLER"; inp.deviceType = INPUT_USE_GAMECONTROLLER; options->input.push_back(inp); options->fullScreenMode = 0; options->windowSize = 3; options->language = ba_BA; options->difficulty = DIFFICULTY_NORMAL; options->playerSelected = 0; options->filter = FILTER_NEAREST; options->vSync = true; options->screenWidth = GAME_WIDTH; options->screenHeight = GAME_HEIGHT; options->integerScale = true; options->keepAspect = true; options->borderSize = 0.0f; options->borderEnabled = false; // Online options->online.enabled = false; options->online.server = ""; options->online.port = 0; options->online.gameID = "coffee_crisis"; options->online.jailerID = ""; options->online.score = 0; } // Carga el fichero de configuración bool Director::loadConfigFile() { // Indicador de éxito en la carga bool success = true; // Variables para manejar el fichero std::string line; std::ifstream file(asset->get("config.txt")); // Si el fichero se puede abrir if (file.good()) { // Procesa el fichero linea a linea std::cout << "Reading file config.txt\n"; while (std::getline(file, line)) { // Comprueba que la linea no sea un comentario if (line.substr(0, 1) != "#") { // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (!setOptions(options, line.substr(0, pos), line.substr(pos + 1, line.length()))) { std::cout << "Warning: file config.txt\n"; std::cout << "unknown parameter " << line.substr(0, pos).c_str() << std::endl; success = false; } } } // Cierra el fichero std::cout << "Closing file config.txt\n\n"; file.close(); } // El fichero no existe else { // Crea el fichero con los valores por defecto saveConfigFile(); } // Normaliza los valores const bool a = options->fullScreenMode == 0; const bool b = options->fullScreenMode == SDL_WINDOW_FULLSCREEN; const bool c = options->fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP; if (!(a || b || c)) { options->fullScreenMode = 0; } if (options->windowSize < 1 || options->windowSize > 4) { options->windowSize = 3; } if (options->language < 0 || options->language > MAX_LANGUAGES) { options->language = en_UK; } return success; } // Guarda el fichero de configuración bool Director::saveConfigFile() { bool success = true; // Crea y abre el fichero de texto std::ofstream file(asset->get("config.txt")); // Escribe en el fichero file << "## VISUAL OPTIONS\n"; if (options->fullScreenMode == 0) { file << "fullScreenMode=0\n"; } else if (options->fullScreenMode == SDL_WINDOW_FULLSCREEN) { file << "fullScreenMode=SDL_WINDOW_FULLSCREEN\n"; } else if (options->fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP) { file << "fullScreenMode=SDL_WINDOW_FULLSCREEN_DESKTOP\n"; } file << "windowSize=" + std::to_string(options->windowSize) + "\n"; if (options->filter == FILTER_NEAREST) { file << "filter=FILTER_NEAREST\n"; } else { file << "filter=FILTER_LINEAL\n"; } file << "vSync=" + boolToString(options->vSync) + "\n"; file << "integerScale=" + boolToString(options->integerScale) + "\n"; file << "keepAspect=" + boolToString(options->keepAspect) + "\n"; file << "borderEnabled=" + boolToString(options->borderEnabled) + "\n"; file << "borderSize=" + std::to_string(options->borderSize) + "\n"; file << "screenWidth=" + std::to_string(options->screenWidth) + "\n"; file << "screenHeight=" + std::to_string(options->screenHeight) + "\n"; file << "\n## OTHER OPTIONS\n"; file << "language=" + std::to_string(options->language) + "\n"; file << "difficulty=" + std::to_string(options->difficulty) + "\n"; file << "input0=" + std::to_string(options->input.at(0).deviceType) + "\n"; file << "input1=" + std::to_string(options->input.at(1).deviceType) + "\n"; file << "\n## ONLINE OPTIONS\n"; file << "enabled=" + boolToString(options->online.enabled) + "\n"; file << "server=" + options->online.server + "\n"; file << "port=" + std::to_string(options->online.port) + "\n"; file << "jailerID=" + options->online.jailerID + "\n"; // Cierra el fichero file.close(); return success; } // Establece el valor de la variable void Director::setSection(section_t section) { this->section = section; } void Director::runLogo() { logo = new Logo(renderer, screen, asset); setSection(logo->run()); delete logo; } void Director::runIntro() { intro = new Intro(renderer, screen, asset, lang); setSection(intro->run()); delete intro; } void Director::runTitle() { title = new Title(renderer, screen, input, asset, options, lang, section); setSection(title->run()); delete title; } void Director::runGame() { const int numPlayers = section.subsection == GAME_SECTION_PLAY_1P ? 1 : 2; game = new Game(numPlayers, 0, renderer, screen, asset, lang, input, false, options); setSection(game->run()); delete game; } void Director::run() { // Bucle principal while (section.name != PROG_SECTION_QUIT) { switch (section.name) { case PROG_SECTION_LOGO: runLogo(); break; case PROG_SECTION_INTRO: runIntro(); break; case PROG_SECTION_TITLE: runTitle(); break; case PROG_SECTION_GAME: runGame(); break; } } } // Inicializa los servicios online void Director::initOnline() { if (!options->online.enabled) { //screen->showText("Modo Offline"); //std::cout << "Modo Offline" << std::endl; return; } // Obten el Jailer ID if (options->online.jailerID == "") { // Jailer ID no definido screen->showText("No ha especificado ningun Jailer ID"); std::cout << "No ha especificado ningun Jailer ID" << std::endl; } else { // Jailer ID iniciado // Establece el servidor y el puerto jscore::init(options->online.server, options->online.port); // Obtiene la información online if (jscore::initOnlineScore(options->online.gameID)) { screen->showText(options->online.jailerID + " ha iniciado sesion"); std::cout << options->online.jailerID << " ha iniciado sesion" << std::endl; } else { screen->showText("Fallo al conectar a " + options->online.server); std::cout << "Fallo al conectar a " << options->online.server << std::endl; } // Obten la puntuación online const int points = jscore::getUserPoints(options->online.gameID, options->online.jailerID); if (points == 0) { // Fallo de conexión o no hay registros screen->showText("No se ha podido obtener la puntuacion online"); std::cout << "No se ha podido obtener la puntuacion online" << std::endl; } else { options->online.score = points; } } } // Asigna variables a partir de dos cadenas bool Director::setOptions(options_t *options, std::string var, std::string value) { // Indicador de éxito en la asignación bool success = true; if (var == "fullScreenMode") { if (value == "SDL_WINDOW_FULLSCREEN_DESKTOP") { options->fullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP; } else if (value == "SDL_WINDOW_FULLSCREEN") { options->fullScreenMode = SDL_WINDOW_FULLSCREEN; } else { options->fullScreenMode = 0; } } else if (var == "windowSize") { options->windowSize = std::stoi(value); if ((options->windowSize < 1) || (options->windowSize > 4)) { options->windowSize = 3; } } else if (var == "filter") { if (value == "FILTER_LINEAL") { options->filter = FILTER_LINEAL; } else { options->filter = FILTER_NEAREST; } } else if (var == "vSync") { options->vSync = stringToBool(value); } else if (var == "integerScale") { options->integerScale = stringToBool(value); } else if (var == "keepAspect") { options->keepAspect = stringToBool(value); } else if (var == "borderEnabled") { options->borderEnabled = stringToBool(value); } else if (var == "borderSize") { options->borderSize = std::stof(value); if (options->borderSize < 0.0f || options->borderSize > 0.5f) { options->borderSize = 0.1f; } } else if (var == "screenWidth") { options->screenWidth = std::stoi(value); } else if (var == "screenHeight") { options->screenHeight = std::stoi(value); } else if (var == "language") { options->language = std::stoi(value); } else if (var == "difficulty") { options->difficulty = std::stoi(value); } else if (var == "input0") { options->input.at(0).deviceType = std::stoi(value); } else if (var == "input1") { options->input.at(1).deviceType = std::stoi(value); } else if (var == "enabled") { options->online.enabled = stringToBool(value); } else if (var == "server") { options->online.server = value; } else if (var == "port") { if (value == "") { value = "0"; } options->online.port = std::stoi(value); } else if (var == "jailerID") { options->online.jailerID = value; } else if (var == "" || var.substr(0, 1) == "#") { } else { success = false; } return success; }