Eliminada la classe Lang
This commit is contained in:
@@ -73,8 +73,7 @@ Director::Director(int argc, char *argv[])
|
|||||||
dbg_init(renderer);
|
dbg_init(renderer);
|
||||||
|
|
||||||
// Crea los objetos
|
// Crea los objetos
|
||||||
lang = new Lang(asset);
|
lang::loadFromFile(asset->get("ba_BA.txt"));
|
||||||
lang->setLang(options->game.language);
|
|
||||||
|
|
||||||
input = new Input(asset->get("gamecontrollerdb.txt"));
|
input = new Input(asset->get("gamecontrollerdb.txt"));
|
||||||
initInput();
|
initInput();
|
||||||
@@ -95,7 +94,6 @@ Director::~Director()
|
|||||||
delete asset;
|
delete asset;
|
||||||
delete input;
|
delete input;
|
||||||
delete screen;
|
delete screen;
|
||||||
delete lang;
|
|
||||||
delete options;
|
delete options;
|
||||||
delete param;
|
delete param;
|
||||||
delete section;
|
delete section;
|
||||||
@@ -523,7 +521,7 @@ void Director::initOptions()
|
|||||||
|
|
||||||
// Opciones de juego
|
// Opciones de juego
|
||||||
options->game.difficulty = DIFFICULTY_NORMAL;
|
options->game.difficulty = DIFFICULTY_NORMAL;
|
||||||
options->game.language = ba_BA;
|
options->game.language = 1;
|
||||||
options->game.autofire = true;
|
options->game.autofire = true;
|
||||||
|
|
||||||
// Opciones de control
|
// Opciones de control
|
||||||
@@ -695,9 +693,9 @@ bool Director::loadConfigFile()
|
|||||||
options->video.window.size = 3;
|
options->video.window.size = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->game.language < 0 || options->game.language > MAX_LANGUAGES)
|
if (options->game.language < 0 || options->game.language > 2)
|
||||||
{
|
{
|
||||||
options->game.language = en_UK;
|
options->game.language = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@@ -896,7 +894,7 @@ void Director::runLogo()
|
|||||||
// Ejecuta la sección con la secuencia de introducción
|
// Ejecuta la sección con la secuencia de introducción
|
||||||
void Director::runIntro()
|
void Director::runIntro()
|
||||||
{
|
{
|
||||||
intro = new Intro(screen, asset, input, lang, options, param, section, getMusic(musics, "intro.ogg"));
|
intro = new Intro(screen, asset, input, options, param, section, getMusic(musics, "intro.ogg"));
|
||||||
intro->run();
|
intro->run();
|
||||||
delete intro;
|
delete intro;
|
||||||
}
|
}
|
||||||
@@ -904,7 +902,7 @@ void Director::runIntro()
|
|||||||
// Ejecuta la sección con el titulo del juego
|
// Ejecuta la sección con el titulo del juego
|
||||||
void Director::runTitle()
|
void Director::runTitle()
|
||||||
{
|
{
|
||||||
title = new Title(screen, asset, input, lang, options, param, section, getMusic(musics, "title.ogg"));
|
title = new Title(screen, asset, input, options, param, section, getMusic(musics, "title.ogg"));
|
||||||
title->run();
|
title->run();
|
||||||
delete title;
|
delete title;
|
||||||
}
|
}
|
||||||
@@ -914,7 +912,7 @@ void Director::runGame()
|
|||||||
{
|
{
|
||||||
const int playerID = section->options;
|
const int playerID = section->options;
|
||||||
const int currentStage = 0;
|
const int currentStage = 0;
|
||||||
game = new Game(playerID, currentStage, GAME_MODE_DEMO_OFF, screen, asset, input, lang, options, param, section, getMusic(musics, "playing.ogg"));
|
game = new Game(playerID, currentStage, GAME_MODE_DEMO_OFF, screen, asset, input, options, param, section, getMusic(musics, "playing.ogg"));
|
||||||
game->run();
|
game->run();
|
||||||
delete game;
|
delete game;
|
||||||
}
|
}
|
||||||
@@ -922,7 +920,7 @@ void Director::runGame()
|
|||||||
// Ejecuta la sección donde se muestran las instrucciones
|
// Ejecuta la sección donde se muestran las instrucciones
|
||||||
void Director::runInstructions()
|
void Director::runInstructions()
|
||||||
{
|
{
|
||||||
instructions = new Instructions(screen, asset, input, lang, options, param, section, getMusic(musics, "title.ogg"));
|
instructions = new Instructions(screen, asset, input, options, param, section, getMusic(musics, "title.ogg"));
|
||||||
instructions->run();
|
instructions->run();
|
||||||
delete instructions;
|
delete instructions;
|
||||||
}
|
}
|
||||||
@@ -930,7 +928,7 @@ void Director::runInstructions()
|
|||||||
// Ejecuta la sección donde se muestra la tabla de puntuaciones
|
// Ejecuta la sección donde se muestra la tabla de puntuaciones
|
||||||
void Director::runHiScoreTable()
|
void Director::runHiScoreTable()
|
||||||
{
|
{
|
||||||
hiScoreTable = new HiScoreTable(screen, asset, input, lang, options, param, section, getMusic(musics, "title.ogg"));
|
hiScoreTable = new HiScoreTable(screen, asset, input, options, param, section, getMusic(musics, "title.ogg"));
|
||||||
hiScoreTable->run();
|
hiScoreTable->run();
|
||||||
delete hiScoreTable;
|
delete hiScoreTable;
|
||||||
}
|
}
|
||||||
@@ -940,7 +938,7 @@ void Director::runDemoGame()
|
|||||||
{
|
{
|
||||||
const int playerID = (rand() % 2) + 1;
|
const int playerID = (rand() % 2) + 1;
|
||||||
const int currentStage = 0;
|
const int currentStage = 0;
|
||||||
demoGame = new Game(playerID, currentStage, GAME_MODE_DEMO_ON, screen, asset, input, lang, options, param, section, nullptr);
|
demoGame = new Game(playerID, currentStage, GAME_MODE_DEMO_ON, screen, asset, input, options, param, section, nullptr);
|
||||||
demoGame->run();
|
demoGame->run();
|
||||||
delete demoGame;
|
delete demoGame;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "intro.h"
|
#include "intro.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
|
#include "lang.h"
|
||||||
#include "logo.h"
|
#include "logo.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "title.h"
|
#include "title.h"
|
||||||
@@ -36,7 +37,6 @@ private:
|
|||||||
HiScoreTable *hiScoreTable; // Objeto para mostrar las mejores puntuaciones online
|
HiScoreTable *hiScoreTable; // Objeto para mostrar las mejores puntuaciones online
|
||||||
Game *demoGame; // Objeto para lanzar la demo del juego
|
Game *demoGame; // Objeto para lanzar la demo del juego
|
||||||
Input *input; // Objeto Input para gestionar las entradas
|
Input *input; // Objeto Input para gestionar las entradas
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
section_t *section; // Sección y subsección actual del programa;
|
section_t *section; // Sección y subsección actual del programa;
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
#define GAME_OVER_COUNTER 350
|
#define GAME_OVER_COUNTER 350
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Game::Game(int playerID, int currentStage, bool demo, Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
Game::Game(int playerID, int currentStage, bool demo, Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
||||||
{
|
{
|
||||||
// Copia los punteros
|
// Copia los punteros
|
||||||
this->screen = screen;
|
this->screen = screen;
|
||||||
this->asset = asset;
|
this->asset = asset;
|
||||||
this->lang = lang;
|
|
||||||
this->input = input;
|
this->input = input;
|
||||||
this->param = param;
|
this->param = param;
|
||||||
this->options = options;
|
this->options = options;
|
||||||
@@ -25,7 +24,7 @@ Game::Game(int playerID, int currentStage, bool demo, Screen *screen, Asset *ass
|
|||||||
// Crea los objetos
|
// Crea los objetos
|
||||||
fade = new Fade(renderer, param);
|
fade = new Fade(renderer, param);
|
||||||
eventHandler = new SDL_Event();
|
eventHandler = new SDL_Event();
|
||||||
scoreboard = new Scoreboard(renderer, asset, lang, options);
|
scoreboard = new Scoreboard(renderer, asset, options);
|
||||||
background = new Background(renderer, asset, param);
|
background = new Background(renderer, asset, param);
|
||||||
explosions = new Explosions();
|
explosions = new Explosions();
|
||||||
enemyFormations = new EnemyFormations(param);
|
enemyFormations = new EnemyFormations(param);
|
||||||
@@ -110,14 +109,14 @@ void Game::init(int playerID)
|
|||||||
// Crea los dos jugadores
|
// Crea los dos jugadores
|
||||||
Player *player1 = new Player(1, (param->game.playArea.firstQuarterX * ((0 * 2) + 1)) - 11, param->game.playArea.rect.h - 30, ¶m->game.playArea.rect, playerTextures[0], playerAnimations);
|
Player *player1 = new Player(1, (param->game.playArea.firstQuarterX * ((0 * 2) + 1)) - 11, param->game.playArea.rect.h - 30, ¶m->game.playArea.rect, playerTextures[0], playerAnimations);
|
||||||
player1->setScoreBoardPanel(SCOREBOARD_LEFT_PANEL);
|
player1->setScoreBoardPanel(SCOREBOARD_LEFT_PANEL);
|
||||||
player1->setName(lang->getText(53));
|
player1->setName(lang::getText(53));
|
||||||
const int controller1 = getController(player1->getId());
|
const int controller1 = getController(player1->getId());
|
||||||
player1->setController(controller1);
|
player1->setController(controller1);
|
||||||
players.push_back(player1);
|
players.push_back(player1);
|
||||||
|
|
||||||
Player *player2 = new Player(2, (param->game.playArea.firstQuarterX * ((1 * 2) + 1)) - 11, param->game.playArea.rect.h - 30, ¶m->game.playArea.rect, playerTextures[1], playerAnimations);
|
Player *player2 = new Player(2, (param->game.playArea.firstQuarterX * ((1 * 2) + 1)) - 11, param->game.playArea.rect.h - 30, ¶m->game.playArea.rect, playerTextures[1], playerAnimations);
|
||||||
player2->setScoreBoardPanel(SCOREBOARD_RIGHT_PANEL);
|
player2->setScoreBoardPanel(SCOREBOARD_RIGHT_PANEL);
|
||||||
player2->setName(lang->getText(54));
|
player2->setName(lang::getText(54));
|
||||||
const int controller2 = getController(player2->getId());
|
const int controller2 = getController(player2->getId());
|
||||||
player2->setController(controller2);
|
player2->setController(controller2);
|
||||||
players.push_back(player2);
|
players.push_back(player2);
|
||||||
@@ -2284,7 +2283,7 @@ void Game::renderMessages()
|
|||||||
// GetReady
|
// GetReady
|
||||||
if ((counter < STAGE_COUNTER) && (!demo.enabled))
|
if ((counter < STAGE_COUNTER) && (!demo.enabled))
|
||||||
{
|
{
|
||||||
textNokiaBig2->write((int)getReadyBitmapPath[counter], param->game.playArea.centerY - 8, lang->getText(75), -2);
|
textNokiaBig2->write((int)getReadyBitmapPath[counter], param->game.playArea.centerY - 8, lang::getText(75), -2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time Stopped
|
// Time Stopped
|
||||||
@@ -2292,7 +2291,7 @@ void Game::renderMessages()
|
|||||||
{
|
{
|
||||||
if ((timeStoppedCounter > 100) || (timeStoppedCounter % 10 > 4))
|
if ((timeStoppedCounter > 100) || (timeStoppedCounter % 10 > 4))
|
||||||
{
|
{
|
||||||
textNokia2->writeDX(TXT_CENTER, param->game.playArea.centerX, param->game.playArea.firstQuarterY, lang->getText(36) + std::to_string(timeStoppedCounter / 10), -1, noColor, 1, shdwTxtColor);
|
textNokia2->writeDX(TXT_CENTER, param->game.playArea.centerX, param->game.playArea.firstQuarterY, lang::getText(36) + std::to_string(timeStoppedCounter / 10), -1, noColor, 1, shdwTxtColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeStoppedCounter > 100)
|
if (timeStoppedCounter > 100)
|
||||||
@@ -2321,11 +2320,11 @@ void Game::renderMessages()
|
|||||||
|
|
||||||
if (stageNum == 10)
|
if (stageNum == 10)
|
||||||
{ // Ultima fase
|
{ // Ultima fase
|
||||||
text = lang->getText(79);
|
text = lang::getText(79);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // X fases restantes
|
{ // X fases restantes
|
||||||
text = std::to_string(11 - stageNum) + lang->getText(38);
|
text = std::to_string(11 - stageNum) + lang::getText(38);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gameCompleted)
|
if (!gameCompleted)
|
||||||
@@ -2334,9 +2333,9 @@ void Game::renderMessages()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // Escribe el texto de juego completado
|
{ // Escribe el texto de juego completado
|
||||||
text = lang->getText(50);
|
text = lang::getText(50);
|
||||||
textNokiaBig2->writeDX(TXT_CENTER, param->game.playArea.centerX, stageBitmapPath[stageBitmapCounter], text, -2, noColor, 1, shdwTxtColor);
|
textNokiaBig2->writeDX(TXT_CENTER, param->game.playArea.centerX, stageBitmapPath[stageBitmapCounter], text, -2, noColor, 1, shdwTxtColor);
|
||||||
textNokia2->writeDX(TXT_CENTER, param->game.playArea.centerX, stageBitmapPath[stageBitmapCounter] + textNokiaBig2->getCharacterSize() + 2, lang->getText(76), -1, noColor, 1, shdwTxtColor);
|
textNokia2->writeDX(TXT_CENTER, param->game.playArea.centerX, stageBitmapPath[stageBitmapCounter] + textNokiaBig2->getCharacterSize() + 2, lang::getText(76), -1, noColor, 1, shdwTxtColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2462,7 +2461,7 @@ void Game::initPaths()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Letrero de GetReady
|
// Letrero de GetReady
|
||||||
const int size = textNokiaBig2->lenght(lang->getText(75), -2);
|
const int size = textNokiaBig2->lenght(lang::getText(75), -2);
|
||||||
|
|
||||||
const float start1 = PLAY_AREA_LEFT - size;
|
const float start1 = PLAY_AREA_LEFT - size;
|
||||||
const float finish1 = param->game.playArea.centerX - (size / 2);
|
const float finish1 = param->game.playArea.centerX - (size / 2);
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ private:
|
|||||||
SDL_Renderer *renderer; // El renderizador de la ventana
|
SDL_Renderer *renderer; // El renderizador de la ventana
|
||||||
Screen *screen; // Objeto encargado de dibujar en pantalla
|
Screen *screen; // Objeto encargado de dibujar en pantalla
|
||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
Input *input; // Manejador de entrada
|
Input *input; // Manejador de entrada
|
||||||
section_t *section; // Seccion actual dentro del juego
|
section_t *section; // Seccion actual dentro del juego
|
||||||
Scoreboard *scoreboard; // Objeto para dibujar el marcador
|
Scoreboard *scoreboard; // Objeto para dibujar el marcador
|
||||||
@@ -451,7 +450,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Game(int playerID, int currentStage, bool demo, Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
Game(int playerID, int currentStage, bool demo, Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Game();
|
~Game();
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
HiScoreTable::HiScoreTable(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
HiScoreTable::HiScoreTable(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
||||||
{
|
{
|
||||||
// Copia punteros
|
// Copia punteros
|
||||||
this->screen = screen;
|
this->screen = screen;
|
||||||
this->asset = asset;
|
this->asset = asset;
|
||||||
this->input = input;
|
this->input = input;
|
||||||
this->lang = lang;
|
|
||||||
this->section = section;
|
this->section = section;
|
||||||
this->options = options;
|
this->options = options;
|
||||||
this->param = param;
|
this->param = param;
|
||||||
@@ -114,7 +113,7 @@ void HiScoreTable::fillTexture()
|
|||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
// Escribe el texto: Mejores puntuaciones
|
// Escribe el texto: Mejores puntuaciones
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, firstLine, lang->getText(42), 1, orangeColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, firstLine, lang::getText(42), 1, orangeColor, 1, shdwTxtColor);
|
||||||
|
|
||||||
// Escribe los nombres de la tabla de puntuaciones
|
// Escribe los nombres de la tabla de puntuaciones
|
||||||
for (int i = 0; i < maxNames; ++i)
|
for (int i = 0; i < maxNames; ++i)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ private:
|
|||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
Input *input; // Objeto pata gestionar la entrada
|
Input *input; // Objeto pata gestionar la entrada
|
||||||
Background *background; // Objeto para dibujar el fondo del juego
|
Background *background; // Objeto para dibujar el fondo del juego
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
Fade *fade; // Objeto para renderizar fades
|
Fade *fade; // Objeto para renderizar fades
|
||||||
Text *text; // Objeto para escribir texto
|
Text *text; // Objeto para escribir texto
|
||||||
JA_Music_t *music; // Musica de fondo
|
JA_Music_t *music; // Musica de fondo
|
||||||
@@ -83,7 +82,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
HiScoreTable(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
HiScoreTable(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~HiScoreTable();
|
~HiScoreTable();
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Instructions::Instructions(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
Instructions::Instructions(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
||||||
{
|
{
|
||||||
// Copia los punteros
|
// Copia los punteros
|
||||||
this->screen = screen;
|
this->screen = screen;
|
||||||
this->asset = asset;
|
this->asset = asset;
|
||||||
this->input = input;
|
this->input = input;
|
||||||
this->lang = lang;
|
|
||||||
this->param = param;
|
this->param = param;
|
||||||
this->section = section;
|
this->section = section;
|
||||||
this->music = music;
|
this->music = music;
|
||||||
@@ -164,31 +163,31 @@ void Instructions::fillTexture()
|
|||||||
int lenght = 0;
|
int lenght = 0;
|
||||||
for (int i = 17; i <= 21; ++i)
|
for (int i = 17; i <= 21; ++i)
|
||||||
{
|
{
|
||||||
const int l = text->lenght(lang->getText(i));
|
const int l = text->lenght(lang::getText(i));
|
||||||
lenght = l > lenght ? l : lenght;
|
lenght = l > lenght ? l : lenght;
|
||||||
}
|
}
|
||||||
const int anchorItem = (param->game.width - (lenght + despX)) / 2;
|
const int anchorItem = (param->game.width - (lenght + despX)) / 2;
|
||||||
|
|
||||||
// Escribe el texto de las instrucciones
|
// Escribe el texto de las instrucciones
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, firstLine, lang->getText(11), 1, orangeColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, firstLine, lang::getText(11), 1, orangeColor, 1, shdwTxtColor);
|
||||||
|
|
||||||
const int anchor1 = firstLine + spacePostHeader;
|
const int anchor1 = firstLine + spacePostHeader;
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceBetweenLines * 0, lang->getText(12), 1, noColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceBetweenLines * 0, lang::getText(12), 1, noColor, 1, shdwTxtColor);
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceBetweenLines * 1, lang->getText(13), 1, noColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceBetweenLines * 1, lang::getText(13), 1, noColor, 1, shdwTxtColor);
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 2, lang->getText(14), 1, noColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 2, lang::getText(14), 1, noColor, 1, shdwTxtColor);
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 3, lang->getText(15), 1, noColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 3, lang::getText(15), 1, noColor, 1, shdwTxtColor);
|
||||||
|
|
||||||
// Escribe el texto de los objetos y sus puntos
|
// Escribe el texto de los objetos y sus puntos
|
||||||
const int anchor2 = anchor1 + spacePreHeader + spaceNewParagraph + spaceBetweenLines * 3;
|
const int anchor2 = anchor1 + spacePreHeader + spaceNewParagraph + spaceBetweenLines * 3;
|
||||||
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor2, lang->getText(16), 1, orangeColor, 1, shdwTxtColor);
|
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param->game.gameArea.centerX, anchor2, lang::getText(16), 1, orangeColor, 1, shdwTxtColor);
|
||||||
|
|
||||||
const int anchor3 = anchor2 + spacePostHeader;
|
const int anchor3 = anchor2 + spacePostHeader;
|
||||||
// const int anchor4 = anchor3 + ((param->game.itemSize + text->getCharacterSize()) / 2);
|
// const int anchor4 = anchor3 + ((param->game.itemSize + text->getCharacterSize()) / 2);
|
||||||
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 0, lang->getText(17), shdwTxtColor);
|
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 0, lang::getText(17), shdwTxtColor);
|
||||||
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 1, lang->getText(18), shdwTxtColor);
|
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 1, lang::getText(18), shdwTxtColor);
|
||||||
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 2, lang->getText(19), shdwTxtColor);
|
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 2, lang::getText(19), shdwTxtColor);
|
||||||
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 3, lang->getText(20), shdwTxtColor);
|
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 3, lang::getText(20), shdwTxtColor);
|
||||||
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 4, lang->getText(21), shdwTxtColor);
|
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 4, lang::getText(21), shdwTxtColor);
|
||||||
|
|
||||||
// Deja el renderizador como estaba
|
// Deja el renderizador como estaba
|
||||||
SDL_SetRenderTarget(renderer, temp);
|
SDL_SetRenderTarget(renderer, temp);
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ private:
|
|||||||
SDL_Texture *texture; // Textura fija con el texto
|
SDL_Texture *texture; // Textura fija con el texto
|
||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
Input *input; // Objeto pata gestionar la entrada
|
Input *input; // Objeto pata gestionar la entrada
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
Text *text; // Objeto para escribir texto
|
Text *text; // Objeto para escribir texto
|
||||||
Tiledbg *tiledbg; // Objeto para dibujar el mosaico animado de fondo
|
Tiledbg *tiledbg; // Objeto para dibujar el mosaico animado de fondo
|
||||||
Fade *fade; // Objeto para renderizar fades
|
Fade *fade; // Objeto para renderizar fades
|
||||||
@@ -90,7 +89,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Instructions(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
Instructions(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Instructions();
|
~Instructions();
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#include "intro.h"
|
#include "intro.h"
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Intro::Intro(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
Intro::Intro(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
||||||
{
|
{
|
||||||
// Copia los punteros
|
// Copia los punteros
|
||||||
this->screen = screen;
|
this->screen = screen;
|
||||||
this->lang = lang;
|
|
||||||
this->asset = asset;
|
this->asset = asset;
|
||||||
this->input = input;
|
this->input = input;
|
||||||
this->param = param;
|
this->param = param;
|
||||||
@@ -101,39 +100,39 @@ Intro::Intro(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Un dia qualsevol de l'any 2000
|
// Un dia qualsevol de l'any 2000
|
||||||
texts[0]->setCaption(lang->getText(27));
|
texts[0]->setCaption(lang::getText(27));
|
||||||
texts[0]->setSpeed(8);
|
texts[0]->setSpeed(8);
|
||||||
|
|
||||||
// Tot esta tranquil a la UPV
|
// Tot esta tranquil a la UPV
|
||||||
texts[1]->setCaption(lang->getText(28));
|
texts[1]->setCaption(lang::getText(28));
|
||||||
texts[1]->setSpeed(8);
|
texts[1]->setSpeed(8);
|
||||||
|
|
||||||
// Fins que un desaprensiu...
|
// Fins que un desaprensiu...
|
||||||
texts[2]->setCaption(lang->getText(29));
|
texts[2]->setCaption(lang::getText(29));
|
||||||
texts[2]->setSpeed(12);
|
texts[2]->setSpeed(12);
|
||||||
|
|
||||||
// HEY! ME ANE A FERME UN CORTAET...
|
// HEY! ME ANE A FERME UN CORTAET...
|
||||||
texts[3]->setCaption(lang->getText(30));
|
texts[3]->setCaption(lang::getText(30));
|
||||||
texts[3]->setSpeed(8);
|
texts[3]->setSpeed(8);
|
||||||
|
|
||||||
// UAAAAAAAAAAAAA!!!
|
// UAAAAAAAAAAAAA!!!
|
||||||
texts[4]->setCaption(lang->getText(31));
|
texts[4]->setCaption(lang::getText(31));
|
||||||
texts[4]->setSpeed(1);
|
texts[4]->setSpeed(1);
|
||||||
|
|
||||||
// Espera un moment...
|
// Espera un moment...
|
||||||
texts[5]->setCaption(lang->getText(32));
|
texts[5]->setCaption(lang::getText(32));
|
||||||
texts[5]->setSpeed(16);
|
texts[5]->setSpeed(16);
|
||||||
|
|
||||||
// Si resulta que no tinc solt!
|
// Si resulta que no tinc solt!
|
||||||
texts[6]->setCaption(lang->getText(33));
|
texts[6]->setCaption(lang::getText(33));
|
||||||
texts[6]->setSpeed(2);
|
texts[6]->setSpeed(2);
|
||||||
|
|
||||||
// MERDA DE MAQUINA!
|
// MERDA DE MAQUINA!
|
||||||
texts[7]->setCaption(lang->getText(34));
|
texts[7]->setCaption(lang::getText(34));
|
||||||
texts[7]->setSpeed(3);
|
texts[7]->setSpeed(3);
|
||||||
|
|
||||||
// Blop... blop... blop...
|
// Blop... blop... blop...
|
||||||
texts[8]->setCaption(lang->getText(35));
|
texts[8]->setCaption(lang::getText(35));
|
||||||
texts[8]->setSpeed(16);
|
texts[8]->setSpeed(16);
|
||||||
|
|
||||||
for (auto text : texts)
|
for (auto text : texts)
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ private:
|
|||||||
Texture *texture; // Textura con los graficos
|
Texture *texture; // Textura con los graficos
|
||||||
SDL_Event *eventHandler; // Manejador de eventos
|
SDL_Event *eventHandler; // Manejador de eventos
|
||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
Input *input; // Objeto pata gestionar la entrada
|
Input *input; // Objeto pata gestionar la entrada
|
||||||
std::vector<SmartSprite *> bitmaps; // Vector con los sprites inteligentes para los dibujos de la intro
|
std::vector<SmartSprite *> bitmaps; // Vector con los sprites inteligentes para los dibujos de la intro
|
||||||
std::vector<Writer *> texts; // Textos de la intro
|
std::vector<Writer *> texts; // Textos de la intro
|
||||||
@@ -64,7 +63,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Intro(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
Intro(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Intro();
|
~Intro();
|
||||||
|
|||||||
@@ -2,72 +2,40 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
// Constructor
|
namespace lang
|
||||||
Lang::Lang(Asset *mAsset)
|
{
|
||||||
{
|
// Inicializa los textos del juego en el idioma seleccionado
|
||||||
this->mAsset = mAsset;
|
bool loadFromFile(std::string filePath)
|
||||||
}
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
Lang::~Lang()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inicializa los textos del juego en el idioma seleccionado
|
|
||||||
bool Lang::setLang(Uint8 lang)
|
|
||||||
{
|
|
||||||
std::string file;
|
|
||||||
|
|
||||||
switch (lang)
|
|
||||||
{
|
{
|
||||||
case es_ES:
|
texts.clear();
|
||||||
file = mAsset->get("es_ES.txt");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case en_UK:
|
bool success = false;
|
||||||
file = mAsset->get("en_UK.txt");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ba_BA:
|
std::ifstream rfile(filePath);
|
||||||
file = mAsset->get("ba_BA.txt");
|
if (rfile.is_open() && rfile.good())
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
file = mAsset->get("en_UK.txt");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < MAX_TEXT_STRINGS; i++)
|
|
||||||
mTextStrings[i] = "";
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
std::ifstream rfile(file);
|
|
||||||
if (rfile.is_open() && rfile.good())
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
std::string line;
|
|
||||||
|
|
||||||
// lee el resto de datos del fichero
|
|
||||||
int index = 0;
|
|
||||||
while (std::getline(rfile, line))
|
|
||||||
{
|
{
|
||||||
// Almacena solo las lineas que no empiezan por # o no esten vacias
|
success = true;
|
||||||
const bool test1 = line.substr(0,1) != "#";
|
std::string line;
|
||||||
const bool test2 = !line.empty();
|
|
||||||
if (test1 && test2)
|
// Lee el resto de datos del fichero
|
||||||
|
while (std::getline(rfile, line))
|
||||||
{
|
{
|
||||||
mTextStrings[index] = line;
|
// Almacena solo las lineas que no empiezan por # o no esten vacias
|
||||||
index++;
|
const bool test1 = line.substr(0, 1) != "#";
|
||||||
}
|
const bool test2 = !line.empty();
|
||||||
};
|
if (test1 && test2)
|
||||||
|
{
|
||||||
|
texts.push_back(line);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
// Obtiene la cadena de texto del indice
|
||||||
}
|
std::string getText(int index)
|
||||||
|
{
|
||||||
// Obtiene la cadena de texto del indice
|
return texts.at(index);
|
||||||
std::string Lang::getText(int index)
|
}
|
||||||
{
|
|
||||||
return mTextStrings[index];
|
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include "common/asset.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// Códigos de idioma
|
namespace lang
|
||||||
#define es_ES 0
|
|
||||||
#define ba_BA 1
|
|
||||||
#define en_UK 2
|
|
||||||
#define MAX_LANGUAGES 3
|
|
||||||
|
|
||||||
// Textos
|
|
||||||
#define MAX_TEXT_STRINGS 100
|
|
||||||
|
|
||||||
// Clase Lang
|
|
||||||
class Lang
|
|
||||||
{
|
{
|
||||||
private:
|
// Variables
|
||||||
Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos
|
std::vector<std::string> texts; // Vector con los textos
|
||||||
std::string mTextStrings[MAX_TEXT_STRINGS]; // Vector con los textos
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Constructor
|
|
||||||
Lang(Asset *mAsset);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~Lang();
|
|
||||||
|
|
||||||
// Inicializa los textos del juego en el idioma seleccionado
|
// Inicializa los textos del juego en el idioma seleccionado
|
||||||
bool setLang(Uint8 lang);
|
bool loadFromFile(std::string filePath);
|
||||||
|
|
||||||
// Obtiene la cadena de texto del indice
|
// Obtiene la cadena de texto del indice
|
||||||
std::string getText(int index);
|
std::string getText(int index);
|
||||||
};
|
}
|
||||||
@@ -2,12 +2,11 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Scoreboard::Scoreboard(SDL_Renderer *renderer, Asset *asset, Lang *lang, options_t *options)
|
Scoreboard::Scoreboard(SDL_Renderer *renderer, Asset *asset, options_t *options)
|
||||||
{
|
{
|
||||||
// Copia los punteros
|
// Copia los punteros
|
||||||
this->renderer = renderer;
|
this->renderer = renderer;
|
||||||
this->asset = asset;
|
this->asset = asset;
|
||||||
this->lang = lang;
|
|
||||||
this->options = options;
|
this->options = options;
|
||||||
|
|
||||||
// Inicializa punteros
|
// Inicializa punteros
|
||||||
@@ -234,7 +233,7 @@ void Scoreboard::fillPanelTextures()
|
|||||||
textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i]));
|
textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i]));
|
||||||
|
|
||||||
// MULT
|
// MULT
|
||||||
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang->getText(55));
|
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(55));
|
||||||
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, std::to_string(mult[i]).substr(0, 3));
|
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, std::to_string(mult[i]).substr(0, 3));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -258,7 +257,7 @@ void Scoreboard::fillPanelTextures()
|
|||||||
|
|
||||||
case SCOREBOARD_MODE_STAGE_INFO:
|
case SCOREBOARD_MODE_STAGE_INFO:
|
||||||
// STAGE
|
// STAGE
|
||||||
textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, lang->getText(57) + std::to_string(stage));
|
textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, lang::getText(57) + std::to_string(stage));
|
||||||
|
|
||||||
// POWERMETER
|
// POWERMETER
|
||||||
powerMeterSprite->setSpriteClip(0, 0, 40, 7);
|
powerMeterSprite->setSpriteClip(0, 0, 40, 7);
|
||||||
@@ -267,7 +266,7 @@ void Scoreboard::fillPanelTextures()
|
|||||||
powerMeterSprite->render();
|
powerMeterSprite->render();
|
||||||
|
|
||||||
// HI-SCORE
|
// HI-SCORE
|
||||||
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang->getText(56));
|
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(56));
|
||||||
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, hiScoreName + " - " +updateScoreText(hiScore));
|
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, hiScoreName + " - " +updateScoreText(hiScore));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ private:
|
|||||||
// Objetos y punteros
|
// Objetos y punteros
|
||||||
SDL_Renderer *renderer; // El renderizador de la ventana
|
SDL_Renderer *renderer; // El renderizador de la ventana
|
||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
Texture *gamePowerMeterTexture; // Textura con el marcador de poder de la fase
|
Texture *gamePowerMeterTexture; // Textura con el marcador de poder de la fase
|
||||||
Sprite *powerMeterSprite; // Sprite para el medidor de poder de la fase
|
Sprite *powerMeterSprite; // Sprite para el medidor de poder de la fase
|
||||||
Text *textScoreBoard; // Fuente para el marcador del juego
|
Text *textScoreBoard; // Fuente para el marcador del juego
|
||||||
@@ -94,7 +93,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Scoreboard(SDL_Renderer *renderer, Asset *asset, Lang *lang, options_t *options);
|
Scoreboard(SDL_Renderer *renderer, Asset *asset, options_t *options);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Scoreboard();
|
~Scoreboard();
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
#include "title.h"
|
#include "title.h"
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Title::Title(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
Title::Title(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music)
|
||||||
{
|
{
|
||||||
// Copia las direcciones de los punteros y objetos
|
// Copia las direcciones de los punteros y objetos
|
||||||
this->screen = screen;
|
this->screen = screen;
|
||||||
this->input = input;
|
this->input = input;
|
||||||
this->asset = asset;
|
this->asset = asset;
|
||||||
this->options = options;
|
this->options = options;
|
||||||
this->lang = lang;
|
|
||||||
this->param = param;
|
this->param = param;
|
||||||
this->section = section;
|
this->section = section;
|
||||||
this->music = music;
|
this->music = music;
|
||||||
@@ -168,7 +167,7 @@ void Title::render()
|
|||||||
// 'PULSA 1P o 2P PARA JUGAR'
|
// 'PULSA 1P o 2P PARA JUGAR'
|
||||||
if (counter % 50 > 14 && !defineButtons->isEnabled())
|
if (counter % 50 > 14 && !defineButtons->isEnabled())
|
||||||
{
|
{
|
||||||
text1->writeDX(TXT_CENTER | TXT_SHADOW, param->game.gameArea.centerX, param->title.pressStartPosition, lang->getText(23), 1, noColor, 1, shadow);
|
text1->writeDX(TXT_CENTER | TXT_SHADOW, param->game.gameArea.centerX, param->title.pressStartPosition, lang::getText(23), 1, noColor, 1, shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mini logo
|
// Mini logo
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ private:
|
|||||||
Screen *screen; // Objeto encargado de dibujar en pantalla
|
Screen *screen; // Objeto encargado de dibujar en pantalla
|
||||||
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
|
||||||
Input *input; // Objeto para leer las entradas de teclado o mando
|
Input *input; // Objeto para leer las entradas de teclado o mando
|
||||||
Lang *lang; // Objeto para gestionar los textos en diferentes idiomas
|
|
||||||
SDL_Event *eventHandler; // Manejador de eventos
|
SDL_Event *eventHandler; // Manejador de eventos
|
||||||
section_t *section; // Indicador para el bucle del titulo
|
section_t *section; // Indicador para el bucle del titulo
|
||||||
Tiledbg *tiledbg; // Objeto para dibujar el mosaico animado de fondo
|
Tiledbg *tiledbg; // Objeto para dibujar el mosaico animado de fondo
|
||||||
@@ -105,7 +104,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Title(Screen *screen, Asset *asset, Input *input, Lang *lang, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
Title(Screen *screen, Asset *asset, Input *input, options_t *options, param_t *param, section_t *section, JA_Music_t *music);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Title();
|
~Title();
|
||||||
|
|||||||
Reference in New Issue
Block a user