Files
coffee_crisis_arcade_edition/source/director.cpp
Sergio Valor Martínez 270d7d1848 Duplicada la font 04b_25 per a tindre versió gris i versió negra. La gris es la que es por modular amb colors.
Eliminada la font nokia que ja no s'estava utilitzant.
Optimitzada la càrrega de fonts al permetre reutilitzar fitxers .txt de altres fonts
2025-02-06 10:31:32 +01:00

821 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 <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO...
#ifndef _WIN32
#include <pwd.h> // Para getpwuid, passwd
#endif
#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 <chrono> // Para chrono
#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 "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, options, OptionsContro...
#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
// 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 // 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();
#ifdef ARCADE
shutdownSystem(section::options == section::Options::QUIT_WITH_CONTROLLER);
#endif
}
// 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/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/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/game_start.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/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/stage_change.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_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/walk.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/tabe_hit.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);
Asset::get()->add(prefix + "/data/gfx/game/game_sun.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_moon.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_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);
}
{ // 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_1_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_2_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_invencible_palette.gif", 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_1_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_2_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_invencible_palette.gif", 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/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);
Asset::get()->add(prefix + "/data/font/04b_25_metal.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/04b_25_grey.png", AssetType::BITMAP);
// 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
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(bool shouldShutdown)
{
if (shouldShutdown)
{
#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
}
}
#endif // ARCADE