Files
coffee_crisis_arcade_edition/source/director.cpp

747 lines
27 KiB
C++

#include "director.h"
#include <SDL2/SDL.h> // for SDL_Init, SDL_Quit, SDL_INIT_EV...
#include <SDL2/SDL_audio.h> // for AUDIO_S16
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_error.h> // for SDL_GetError
#include <SDL2/SDL_gamecontroller.h> // for SDL_CONTROLLER_BUTTON_B, SDL_CO...
#include <SDL2/SDL_hints.h> // for SDL_SetHint, SDL_HINT_RENDER_DR...
#include <SDL2/SDL_scancode.h> // for SDL_SCANCODE_0, SDL_SCANCODE_DOWN
#include <SDL2/SDL_stdinc.h> // for SDL_bool, Uint32
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <cstdlib> // for system
#include <errno.h> // for errno, EEXIST, EACCES, ENAMETOO...
#include <stdio.h> // for printf, perror
#include <string.h> // for strcmp
#include <sys/stat.h> // for mkdir, stat, S_IRWXU
#include <unistd.h> // for getuid
#include <cstdlib> // for exit, EXIT_FAILURE, rand, srand
#include <iostream> // for basic_ostream, operator<<, cout
#include <memory> // for make_unique, unique_ptr
#include <string> // for operator+, allocator, char_traits
#include "asset.h" // for Asset, AssetType
#include "dbgtxt.h" // for dbg_init
#include "game.h" // for Game, GAME_MODE_DEMO_OFF, GAME_...
#include "global_inputs.h" // for init
#include "hiscore_table.h" // for HiScoreTable
#include "input.h" // for Input, InputType
#include "instructions.h" // for Instructions
#include "intro.h" // for Intro
#include "jail_audio.h" // for JA_LoadMusic, JA_LoadSound, JA_...
#include "lang.h" // for Code, loadFromFile
#include "logo.h" // for Logo
#include "manage_hiscore_table.h" // for ManageHiScoreTable
#include "notifier.h" // for Notifier
#include "on_screen_help.h" // for OnScreenHelp
#include "options.h" // for options, loadOptionsFile, saveO...
#include "param.h" // for param, loadParamsFromFile
#include "screen.h" // for Screen
#include "section.h" // for Name, name, Options, options
#include "title.h" // for Title
#include "utils.h" // for MusicFile, SoundFile, Options
#ifndef _WIN32
#include <pwd.h> // for getpwuid, passwd
#endif
// Constructor
Director::Director(int argc, const char *argv[])
{
#ifdef RECORDING
section::name = section::Name::GAME;
section::options = section::Options::GAME_PLAY_1P;
#elif DEBUG
section::name = section::Name::LOGO;
#else
section::name = section::Name::LOGO;
#endif
#ifndef VERBOSE
// Deshabilita todos los std::cout
std::ostream null_stream(nullptr);
std::streambuf *orig_buf = std::cout.rdbuf(null_stream.rdbuf());
#endif
// Comprueba los parametros del programa
checkProgramArguments(argc, argv);
// Crea la carpeta del sistema donde guardar datos
createSystemFolder("jailgames");
createSystemFolder("jailgames/coffee_crisis_arcade_edition");
// Crea el objeto que controla los ficheros de recursos
Asset::init(executable_path_);
// Si falta algún fichero no inicia el programa
if (!setFileList())
{
exit(EXIT_FAILURE);
}
// Carga el fichero de configuración
loadOptionsFile(Asset::get()->get("config.txt"));
// Carga los parametros para configurar el juego
#ifdef ANBERNIC
const std::string paramFilePath = asset->get("param_320x240.txt");
#else
const std::string paramFilePath = param_file_argument_ == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt");
#endif
loadParams(paramFilePath);
// Carga el fichero de puntuaciones
auto manager = std::make_unique<ManageHiScoreTable>(&options.game.hi_score_table);
manager->loadFromFile(Asset::get()->get("score.bin"));
// Inicializa SDL
initSDL();
// Inicializa JailAudio
initJailAudio();
// Inicializa el texto de debug
dbg_init(renderer_);
// Crea los objetos
lang::loadFromFile(getLangFile((lang::Code)options.game.language));
Input::init(Asset::get()->get("gamecontrollerdb.txt"));
initInput();
Screen::init(window_, renderer_);
Notifier::init(renderer_, std::string(), Asset::get()->get("8bithud.png"), Asset::get()->get("8bithud.txt"), Asset::get()->get("notify.wav"));
OnScreenHelp::init();
// Carga los sonidos del juego
loadSounds();
// Carga las musicas del juego
loadMusics();
globalInputs::init();
}
Director::~Director()
{
saveOptionsFile(Asset::get()->get("config.txt"));
Asset::destroy();
Input::destroy();
Screen::destroy();
Notifier::destroy();
OnScreenHelp::destroy();
sounds_.clear();
musics_.clear();
SDL_DestroyRenderer(renderer_);
SDL_DestroyWindow(window_);
SDL_Quit();
}
/// Inicializa el objeto input
void Director::initInput()
{
// Busca si hay mandos conectados
Input::get()->discoverGameControllers();
// Teclado - Movimiento del jugador
Input::get()->bindKey(InputType::UP, SDL_SCANCODE_UP);
Input::get()->bindKey(InputType::DOWN, SDL_SCANCODE_DOWN);
Input::get()->bindKey(InputType::LEFT, SDL_SCANCODE_LEFT);
Input::get()->bindKey(InputType::RIGHT, SDL_SCANCODE_RIGHT);
Input::get()->bindKey(InputType::FIRE_LEFT, SDL_SCANCODE_Q);
Input::get()->bindKey(InputType::FIRE_CENTER, SDL_SCANCODE_W);
Input::get()->bindKey(InputType::FIRE_RIGHT, SDL_SCANCODE_E);
Input::get()->bindKey(InputType::START, SDL_SCANCODE_RETURN);
// Teclado - Control del programa
Input::get()->bindKey(InputType::SERVICE, SDL_SCANCODE_0);
Input::get()->bindKey(InputType::EXIT, SDL_SCANCODE_ESCAPE);
Input::get()->bindKey(InputType::PAUSE, SDL_SCANCODE_P);
Input::get()->bindKey(InputType::WINDOW_DEC_SIZE, SDL_SCANCODE_F1);
Input::get()->bindKey(InputType::WINDOW_INC_SIZE, SDL_SCANCODE_F2);
Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3);
Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4);
Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F6);
Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10);
// Asigna botones a inputs
const int num_gamepads = Input::get()->getNumControllers();
for (int i = 0; i < num_gamepads; ++i)
{
// Mando - Movimiento del jugador
Input::get()->bindGameControllerButton(i, InputType::UP, SDL_CONTROLLER_BUTTON_DPAD_UP);
Input::get()->bindGameControllerButton(i, InputType::DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
Input::get()->bindGameControllerButton(i, InputType::LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
Input::get()->bindGameControllerButton(i, InputType::RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
Input::get()->bindGameControllerButton(i, InputType::FIRE_LEFT, SDL_CONTROLLER_BUTTON_X);
Input::get()->bindGameControllerButton(i, InputType::FIRE_CENTER, SDL_CONTROLLER_BUTTON_Y);
Input::get()->bindGameControllerButton(i, InputType::FIRE_RIGHT, SDL_CONTROLLER_BUTTON_B);
Input::get()->bindGameControllerButton(i, InputType::START, SDL_CONTROLLER_BUTTON_START);
// Mando - Control del programa
Input::get()->bindGameControllerButton(i, InputType::SERVICE, SDL_CONTROLLER_BUTTON_BACK);
Input::get()->bindGameControllerButton(i, InputType::EXIT, InputType::START);
Input::get()->bindGameControllerButton(i, InputType::PAUSE, InputType::FIRE_RIGHT);
Input::get()->bindGameControllerButton(i, InputType::VIDEO_SHADERS, InputType::FIRE_LEFT);
Input::get()->bindGameControllerButton(i, InputType::MUTE, InputType::LEFT);
Input::get()->bindGameControllerButton(i, InputType::SHOWINFO, InputType::RIGHT);
Input::get()->bindGameControllerButton(i, InputType::RESET, InputType::FIRE_CENTER);
Input::get()->bindGameControllerButton(i, InputType::CONFIG, InputType::DOWN);
Input::get()->bindGameControllerButton(i, InputType::SWAP_CONTROLLERS, InputType::UP);
}
// Mapea las asignaciones a los botones desde el archivo de configuración, si se da el caso
for (int i = 0; i < num_gamepads; ++i)
for (int index = 0; index < (int)options.controller.size(); ++index)
if (Input::get()->getControllerName(i) == options.controller[index].name)
{
options.controller[index].plugged = true;
for (int j = 0; j < (int)options.controller[index].inputs.size(); ++j)
{
Input::get()->bindGameControllerButton(i, options.controller[index].inputs[j], options.controller[index].buttons[j]);
}
}
// Asigna botones a inputs desde otros inputs
for (int i = 0; i < num_gamepads; ++i)
{
Input::get()->bindGameControllerButton(i, InputType::EXIT, InputType::START);
Input::get()->bindGameControllerButton(i, InputType::RESET, InputType::FIRE_CENTER);
Input::get()->bindGameControllerButton(i, InputType::PAUSE, InputType::FIRE_RIGHT);
Input::get()->bindGameControllerButton(i, InputType::VIDEO_SHADERS, InputType::FIRE_LEFT);
Input::get()->bindGameControllerButton(i, InputType::MUTE, InputType::LEFT);
Input::get()->bindGameControllerButton(i, InputType::SHOWINFO, InputType::RIGHT);
Input::get()->bindGameControllerButton(i, InputType::CONFIG, InputType::DOWN);
Input::get()->bindGameControllerButton(i, InputType::SWAP_CONTROLLERS, InputType::UP);
}
// Guarda las asignaciones de botones en las opciones
for (int i = 0; i < num_gamepads; ++i)
{
options.controller[i].name = Input::get()->getControllerName(i);
for (int j = 0; j < (int)options.controller[i].inputs.size(); ++j)
{
options.controller[i].buttons[j] = Input::get()->getControllerBinding(i, options.controller[i].inputs[j]);
}
}
}
// Inicializa JailAudio
void Director::initJailAudio()
{
JA_Init(48000, AUDIO_S16, 2);
JA_EnableMusic(options.audio.music.enabled);
JA_EnableSound(options.audio.sound.enabled);
JA_SetMusicVolume(options.audio.music.volume);
JA_SetSoundVolume(options.audio.sound.volume);
}
// Arranca SDL y crea la ventana
bool Director::initSDL()
{
// Indicador de éxito
auto success = true;
// Inicializa SDL
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL could not initialize!\nSDL Error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
// Inicia el generador de numeros aleatorios
std::srand(static_cast<unsigned int>(SDL_GetTicks()));
// Muestra información de la pantalla
/*std::cout << "\nDisplay modes list:" << std::endl;
for (int i = 0; i < SDL_GetNumDisplayModes(0); ++i)
{
SDL_DisplayMode DM;
SDL_GetDisplayMode(0,i,&DM);
std::cout << " - " + std::to_string(DM.w) + "x" + std::to_string(DM.h) + " @ " + std::to_string(DM.refresh_rate) + "Hz" << std::endl;
}*/
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
std::cout << "\nCurrent display mode: " + std::to_string(DM.w) + "x" + std::to_string(DM.h) + " @ " + std::to_string(DM.refresh_rate) + "Hz" << std::endl;
std::cout << "Window resolution : " + std::to_string(param.game.width) + "x" + std::to_string(param.game.height) + " x" + std::to_string(options.video.window.size) << std::endl;
// Establece el filtro de la textura
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(static_cast<int>(options.video.filter)).c_str()))
{
std::cout << "Warning: texture filtering not enabled!\n";
}
#ifndef NO_SHADERS
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"))
{
std::cout << "Warning: opengl not enabled!\n";
}
#endif // NO_SHADERS
// Crea la ventana
window_ = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, param.game.width * options.video.window.size, param.game.height * options.video.window.size, SDL_WINDOW_HIDDEN);
if (!window_)
{
std::cout << "Window could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
// Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones
Uint32 flags = 0;
if (options.video.v_sync)
{
flags = SDL_RENDERER_PRESENTVSYNC;
}
#ifndef NO_SHADERS
// La aceleración se activa según el define
flags = flags | SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
#endif
renderer_ = SDL_CreateRenderer(window_, -1, flags);
if (!renderer_)
{
std::cout << "Renderer could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
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_, param.game.width, param.game.height);
SDL_RenderSetIntegerScale(renderer_, static_cast<SDL_bool>(options.video.integer_scale));
// Establece el modo de mezcla
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
}
}
}
std::cout << std::endl;
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::get()->add(system_folder_ + "/config.txt", 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::DATA);
Asset::get()->add(prefix + "/data/config/demo2.bin", AssetType::DATA);
Asset::get()->add(prefix + "/data/config/gamecontrollerdb.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);
// Sonidos
Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble3.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble4.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bullet.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/coffeeout.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/hiscore.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/itemdrop.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/itempickup.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/player_collision.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/stage_change.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/title.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/clock.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND);
// Shaders
Asset::get()->add(prefix + "/data/shaders/crtpi.glsl", AssetType::DATA);
// Texturas
Asset::get()->add(prefix + "/data/gfx/controllers/controllers.png", AssetType::BITMAP);
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);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon4.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon4.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);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion4.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion4.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
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_text/game_text_1000_points.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_2500_points.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_5000_points.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_powerup.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_one_hit.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/intro/intro.png", AssetType::BITMAP);
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);
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_coffee_machine.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION);
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);
Asset::get()->add(prefix + "/data/gfx/player/player1.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player1_pal1.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_pal2.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_pal3.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player2_pal1.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_pal2.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_pal3.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/player/player_power.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player_power_pal.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player_power.ani", AssetType::ANIMATION);
// Fuentes de texto
Asset::get()->add(prefix + "/data/font/8bithud.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/8bithud.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia_big2.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia2.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia2.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia_big2.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2_big.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2_big.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2_pal1.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/font/smb2.txt", AssetType::FONT);
// Textos
Asset::get()->add(prefix + "/data/lang/es_ES.txt", AssetType::LANG);
Asset::get()->add(prefix + "/data/lang/en_UK.txt", AssetType::LANG);
Asset::get()->add(prefix + "/data/lang/ba_BA.txt", AssetType::LANG);
return Asset::get()->check();
}
// Carga los parametros para configurar el juego
void Director::loadParams(const std::string &file_path)
{
loadParamsFromFile(file_path);
}
// Comprueba los parametros del programa
void Director::checkProgramArguments(int argc, const char *argv[])
{
// Establece la ruta del programa
executable_path_ = argv[0];
// Valores por defecto
param_file_argument_.clear();
// Comprueba el resto de parámetros
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--320x240") == 0)
{
param_file_argument_ = argv[i];
}
}
}
// 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);
}
}
}
}
// Carga los sonidos del juego
void Director::loadSounds()
{
// Obtiene la lista con las rutas a los ficheros de sonidos
auto list = Asset::get()->getListByType(AssetType::SOUND);
sounds_.clear();
for (const auto &l : list)
{
auto last_index = l.find_last_of('/') + 1;
auto name = l.substr(last_index);
sounds_.emplace_back(SoundFile{name, JA_LoadSound(l.c_str())});
}
}
// Carga las musicas del juego
void Director::loadMusics()
{
// Obtiene la lista con las rutas a los ficheros musicales
auto list = Asset::get()->getListByType(AssetType::MUSIC);
musics_.clear();
for (const auto &l : list)
{
auto last_index = l.find_last_of('/') + 1;
auto name = l.substr(last_index);
musics_.emplace_back(MusicFile{name, JA_LoadMusic(l.c_str())});
}
}
// Ejecuta la sección con el logo
void Director::runLogo()
{
auto logo = std::make_unique<Logo>();
logo->run();
}
// Ejecuta la sección con la secuencia de introducción
void Director::runIntro()
{
auto intro = std::make_unique<Intro>(getMusic(musics_, "intro.ogg"));
intro->run();
}
// Ejecuta la sección con el título del juego
void Director::runTitle()
{
auto title = std::make_unique<Title>(getMusic(musics_, "title.ogg"));
title->run();
}
// Ejecuta la sección donde se juega al juego
void Director::runGame()
{
const auto player_id = section::options == section::Options::GAME_PLAY_1P ? 1 : 2;
constexpr auto current_stage = 0;
auto game = std::make_unique<Game>(player_id, current_stage, GAME_MODE_DEMO_OFF, getMusic(musics_, "playing.ogg"));
game->run();
}
// Ejecuta la sección donde se muestran las instrucciones
void Director::runInstructions()
{
auto instructions = std::make_unique<Instructions>(getMusic(musics_, "title.ogg"));
instructions->run();
}
// Ejecuta la sección donde se muestra la tabla de puntuaciones
void Director::runHiScoreTable()
{
auto hi_score_table = std::make_unique<HiScoreTable>(getMusic(musics_, "title.ogg"));
hi_score_table->run();
}
// Ejecuta el juego en modo demo
void Director::runDemoGame()
{
const auto player_id = (rand() % 2) + 1;
constexpr auto current_stage = 0;
auto game = std::make_unique<Game>(player_id, current_stage, GAME_MODE_DEMO_ON, nullptr);
game->run();
}
int Director::run()
{
// Bucle principal
while (section::name != section::Name::QUIT)
{
switch (section::name)
{
case section::Name::INIT:
section::name = section::Name::LOGO;
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;
default:
break;
}
}
#ifdef ARCADE
// Comprueba si ha de apagar el sistema
if (section::options == section::Options::QUIT_SHUTDOWN)
shutdownSystem();
#endif
const int return_code = section::options == section::Options::QUIT_NORMAL ? 0 : 1;
return return_code;
}
// Obtiene una fichero a partir de un lang::Code
std::string Director::getLangFile(lang::Code code)
{
switch (code)
{
case lang::Code::ba_BA:
return Asset::get()->get("ba_BA.txt");
break;
case lang::Code::es_ES:
return Asset::get()->get("es_ES.txt");
break;
case lang::Code::en_UK:
return Asset::get()->get("en_UK.txt");
break;
default:
break;
}
return Asset::get()->get("en_UK.txt");
}
// Apaga el sistema
void Director::shutdownSystem()
{
#ifdef _WIN32
// Apaga el sistema en Windows
system("shutdown /s /t 0");
#elif __APPLE__
// Apaga el sistema en macOS
system("sudo shutdown -h now");
#elif __linux__
// Apaga el sistema en Linux
system("shutdown -h now");
#else
// Sistema operativo no compatible
#error "Sistema operativo no soportado"
#endif
}