Afegits nous audios i veus Completat el comportament del enemic nou Ampliat el numero máxim de sons simultanis
812 lines
28 KiB
C++
812 lines
28 KiB
C++
// IWYU pragma: no_include <bits/chrono.h>
|
|
#include "director.h"
|
|
#include <SDL2/SDL.h> // Para SDL_Init, SDL_Quit, SDL_INIT_EV...
|
|
#include <SDL2/SDL_audio.h> // Para AUDIO_S16
|
|
#include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
|
|
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
|
#include <SDL2/SDL_gamecontroller.h> // Para SDL_CONTROLLER_BUTTON_B, SDL_CO...
|
|
#include <SDL2/SDL_hints.h> // Para SDL_SetHint, SDL_HINT_RENDER_DR...
|
|
#include <SDL2/SDL_scancode.h> // Para SDL_SCANCODE_0, SDL_SCANCODE_DOWN
|
|
#include <SDL2/SDL_stdinc.h> // Para SDL_bool, Uint32
|
|
#include <chrono> // Para duration, system_clock
|
|
#include <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO...
|
|
#include <stdio.h> // Para printf, perror
|
|
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU
|
|
#include <unistd.h> // Para getuid
|
|
#include <algorithm> // Para min
|
|
#include <cstdlib> // Para exit, EXIT_FAILURE, size_t, rand
|
|
#include <iostream> // Para basic_ostream, operator<<, basi...
|
|
#include <memory> // Para make_unique, unique_ptr
|
|
#include <stdexcept> // Para runtime_error
|
|
#include <string> // Para operator+, char_traits, allocator
|
|
#include <vector> // Para vector
|
|
#include "asset.h" // Para Asset, AssetType
|
|
#include "credits.h" // Para Credits
|
|
#include "dbgtxt.h" // Para dbg_init
|
|
#include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_...
|
|
#include "global_inputs.h" // Para init
|
|
#include "hiscore_table.h" // Para HiScoreTable
|
|
#include "input.h" // Para Input, InputType
|
|
#include "instructions.h" // Para Instructions
|
|
#include "intro.h" // Para Intro
|
|
#include "jail_audio.h" // Para JA_SetMusicVolume, JA_SetSoundV...
|
|
#include "lang.h" // Para Code, loadFromFile
|
|
#include "logo.h" // Para Logo
|
|
#include "manage_hiscore_table.h" // Para ManageHiScoreTable
|
|
#include "notifier.h" // Para Notifier
|
|
#include "on_screen_help.h" // Para OnScreenHelp
|
|
#include "options.h" // Para Options, OptionsController, opt...
|
|
#include "param.h" // Para Param, ParamGame, param, loadPa...
|
|
#include "resource.h" // Para Resource
|
|
#include "screen.h" // Para Screen
|
|
#include "section.h" // Para Name, Options, name, options
|
|
#include "title.h" // Para Title
|
|
#include "utils.h" // Para Overrides, overrides
|
|
|
|
#ifndef _WIN32
|
|
#include <pwd.h> // para 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::GAME;
|
|
#else // NORMAL GAME
|
|
section::name = section::Name::LOGO;
|
|
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
|
|
#endif
|
|
|
|
#ifndef VERBOSE
|
|
// Deshabilita todos los std::cout
|
|
std::ostream null_stream(nullptr);
|
|
orig_buf = std::cout.rdbuf(null_stream.rdbuf());
|
|
#endif
|
|
|
|
std::cout << "Game start" << std::endl;
|
|
|
|
// Inicia la semilla aleatoria
|
|
unsigned int seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
|
|
std::srand(seed);
|
|
|
|
// 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();
|
|
std::cout << "\nBye!" << std::endl;
|
|
}
|
|
|
|
// Inicializa todo
|
|
void Director::init()
|
|
{
|
|
Asset::init(executable_path_); // Crea el objeto que controla los ficheros de recursos
|
|
setFileList(); // Crea el indice de ficheros
|
|
loadOptionsFile(Asset::get()->get("config.txt")); // Carga el fichero de configuración
|
|
loadParams(); // Carga los parametros
|
|
loadScoreFile(); // Carga el fichero de puntuaciones
|
|
|
|
// Inicializa y crea el resto de objetos
|
|
initSDL();
|
|
initJailAudio();
|
|
dbg_init(renderer_);
|
|
lang::loadFromFile(getLangFile(static_cast<lang::Code>(options.game.language)));
|
|
Screen::init(window_, renderer_);
|
|
Resource::init();
|
|
Input::init(Asset::get()->get("gamecontrollerdb.txt"));
|
|
bindInputs();
|
|
Notifier::init(std::string(), Resource::get()->getText("8bithud"));
|
|
OnScreenHelp::init();
|
|
}
|
|
|
|
// Cierra todo
|
|
void Director::close()
|
|
{
|
|
saveOptionsFile(Asset::get()->get("config.txt"));
|
|
|
|
Asset::destroy();
|
|
Resource::destroy();
|
|
Input::destroy();
|
|
Screen::destroy();
|
|
Notifier::destroy();
|
|
OnScreenHelp::destroy();
|
|
|
|
JA_Quit();
|
|
|
|
SDL_DestroyRenderer(renderer_);
|
|
SDL_DestroyWindow(window_);
|
|
|
|
SDL_Quit();
|
|
}
|
|
|
|
// 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 paramFilePath = overrides.param_file == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt");
|
|
#endif
|
|
loadParamsFromFile(paramFilePath);
|
|
}
|
|
|
|
// Carga el fichero de puntuaciones
|
|
void Director::loadScoreFile()
|
|
{
|
|
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
|
|
if (overrides.clear_hi_score_table)
|
|
{
|
|
manager->clear();
|
|
}
|
|
else
|
|
{
|
|
manager->loadFromFile(Asset::get()->get("score.bin"));
|
|
}
|
|
}
|
|
|
|
// Asigna los botones y teclas al objeto Input
|
|
void Director::bindInputs()
|
|
{
|
|
// 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::AUTO_FIRE, SDL_SCANCODE_F6);
|
|
Input::get()->bindKey(InputType::CHANGE_LANG, SDL_SCANCODE_F7);
|
|
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F8);
|
|
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);
|
|
}
|
|
|
|
// 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::get()->getControllerName(i) == controller.name)
|
|
{
|
|
for (size_t j = 0; j < controller.inputs.size(); ++j)
|
|
{
|
|
Input::get()->bindGameControllerButton(i, controller.inputs.at(j), controller.buttons.at(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 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::get()->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::get()->getControllerBinding(i, options.controllers.at(i).inputs.at(j));
|
|
}
|
|
}
|
|
|
|
// Asegura que algún jugador tenga el teclado asignado
|
|
if (getPlayerWhoUsesKeyboard() == 0)
|
|
{
|
|
setKeyboardToPlayer(1);
|
|
}
|
|
}
|
|
|
|
// Inicializa JailAudio
|
|
void Director::initJailAudio()
|
|
{
|
|
JA_Init(48000, AUDIO_S16, 2);
|
|
if (options.audio.enabled)
|
|
{
|
|
JA_SetMusicVolume(to_JA_volume(options.audio.music.volume));
|
|
JA_SetSoundVolume(to_JA_volume(options.audio.sound.volume));
|
|
}
|
|
else
|
|
{
|
|
JA_SetMusicVolume(0);
|
|
JA_SetSoundVolume(0);
|
|
}
|
|
}
|
|
|
|
// 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
|
|
{
|
|
/*
|
|
// 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 << " - " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl;
|
|
}
|
|
*/
|
|
|
|
// Obtiene información sobre la pantalla
|
|
SDL_DisplayMode DM;
|
|
SDL_GetCurrentDisplayMode(0, &DM);
|
|
|
|
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
|
|
options.video.window.max_size = std::min(DM.w / param.game.width, DM.h / param.game.height);
|
|
options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
|
|
|
|
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego
|
|
std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl;
|
|
std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << 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
|
|
|
|
// 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
|
|
{
|
|
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
|
|
SDL_RenderSetLogicalSize(renderer_, param.game.width, param.game.height);
|
|
SDL_RenderSetIntegerScale(renderer_, static_cast<SDL_bool>(options.video.integer_scale));
|
|
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
return success;
|
|
}
|
|
|
|
// 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_ + "/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);
|
|
Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC);
|
|
|
|
// Sonidos
|
|
Asset::get()->add(prefix + "/data/sound/game_start.wav", AssetType::SOUND);
|
|
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);
|
|
Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND);
|
|
Asset::get()->add(prefix + "/data/sound/voice_coffee.wav", AssetType::SOUND);
|
|
Asset::get()->add(prefix + "/data/sound/voice_power_up.wav", AssetType::SOUND);
|
|
Asset::get()->add(prefix + "/data/sound/voice_no.wav", AssetType::SOUND);
|
|
Asset::get()->add(prefix + "/data/sound/voice_get_ready.wav", AssetType::SOUND);
|
|
Asset::get()->add(prefix + "/data/sound/tabe.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
|
|
|
|
{ // Controllers
|
|
Asset::get()->add(prefix + "/data/gfx/controllers/controllers.png", AssetType::BITMAP);
|
|
}
|
|
|
|
{ // Balloons
|
|
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);
|
|
}
|
|
|
|
{ // Explosions
|
|
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);
|
|
}
|
|
|
|
{ // Power Ball
|
|
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.png", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.ani", AssetType::ANIMATION);
|
|
}
|
|
|
|
{ // Bala
|
|
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
|
|
}
|
|
|
|
{ // Tabe
|
|
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.png", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.ani", AssetType::ANIMATION);
|
|
}
|
|
|
|
{ // 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);
|
|
}
|
|
|
|
{ // Intro
|
|
Asset::get()->add(prefix + "/data/gfx/intro/intro.png", AssetType::BITMAP);
|
|
}
|
|
|
|
{ // 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);
|
|
}
|
|
|
|
{ // 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_coffee_machine.png", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION);
|
|
}
|
|
|
|
{ // 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);
|
|
}
|
|
|
|
{ // Jugador 1
|
|
Asset::get()->add(prefix + "/data/gfx/player/player1.gif", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player1_one_coffee_palette.pal", AssetType::PALETTE);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player1_two_coffee_palette.pal", AssetType::PALETTE);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player1_all_white_palette.pal", AssetType::PALETTE);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player1_power.png", AssetType::BITMAP);
|
|
}
|
|
|
|
{ // Jugador 2
|
|
Asset::get()->add(prefix + "/data/gfx/player/player2.gif", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player2_one_coffee_palette.pal", AssetType::PALETTE);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player2_two_coffee_palette.pal", AssetType::PALETTE);
|
|
Asset::get()->add(prefix + "/data/gfx/player/player2_all_white_palette.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);
|
|
}
|
|
|
|
// 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/nokia.png", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/font/nokia.txt", AssetType::FONT);
|
|
Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::BITMAP);
|
|
Asset::get()->add(prefix + "/data/font/smb2_palette1.pal", AssetType::PALETTE);
|
|
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);
|
|
|
|
// 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);
|
|
|
|
// 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, const char *argv[])
|
|
{
|
|
// Establece la ruta del programa
|
|
executable_path_ = 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>();
|
|
logo->run();
|
|
}
|
|
|
|
// Ejecuta la sección con la secuencia de introducción
|
|
void Director::runIntro()
|
|
{
|
|
auto intro = std::make_unique<Intro>();
|
|
intro->run();
|
|
}
|
|
|
|
// Ejecuta la sección con el título del juego
|
|
void Director::runTitle()
|
|
{
|
|
auto title = std::make_unique<Title>();
|
|
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;
|
|
#ifdef DEBUG
|
|
constexpr auto current_stage = 0;
|
|
#else
|
|
constexpr auto current_stage = 0;
|
|
#endif
|
|
auto game = std::make_unique<Game>(player_id, current_stage, GAME_MODE_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 = (rand() % 2) + 1;
|
|
constexpr auto current_stage = 0;
|
|
auto game = std::make_unique<Game>(player_id, current_stage, GAME_MODE_DEMO_ON);
|
|
game->run();
|
|
}
|
|
|
|
// Ejecuta la sección init
|
|
void Director::runInit()
|
|
{
|
|
if (section::options == section::Options::RELOAD)
|
|
{
|
|
Resource::get()->reload();
|
|
}
|
|
section::name = section::Name::LOGO;
|
|
}
|
|
|
|
int Director::run()
|
|
{
|
|
// Bucle principal
|
|
while (section::name != section::Name::QUIT)
|
|
{
|
|
switch (section::name)
|
|
{
|
|
case section::Name::INIT:
|
|
runInit();
|
|
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;
|
|
}
|
|
}
|
|
|
|
std::string return_code;
|
|
switch (section::options)
|
|
{
|
|
case section::Options::QUIT_WITH_KEYBOARD:
|
|
return_code = "with keyboard";
|
|
break;
|
|
case section::Options::QUIT_WITH_CONTROLLER:
|
|
return_code = "with controller";
|
|
break;
|
|
default:
|
|
return_code = "from event";
|
|
break;
|
|
}
|
|
|
|
std::cout << "\nGame end " << return_code << std::endl;
|
|
|
|
#ifndef VERBOSE
|
|
// Habilita de nuevo los std::cout
|
|
std::cout.rdbuf(orig_buf);
|
|
#endif
|
|
#ifdef ARCADE
|
|
// Comprueba si ha de apagar el sistema
|
|
if (section::options == section::Options::QUIT_WITH_CONTROLLER)
|
|
shutdownSystem();
|
|
#endif
|
|
|
|
return (section::options == section::Options::QUIT_WITH_CONTROLLER) ? 1 : 0;
|
|
}
|
|
|
|
// 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");
|
|
}
|
|
|
|
#ifdef ARCADE
|
|
// 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
|
|
}
|
|
#endif // ARCADE
|