#include "game.h"
#include "common/jscore.h"

// Constructor
Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *asset, Lang *lang, Input *input, bool demo, options_t *options, section_t *section)
{
	// Copia los punteros
	this->renderer = renderer;
	this->screen = screen;
	this->asset = asset;
	this->lang = lang;
	this->input = input;
	this->options = options;
	this->section = section;

	// Pasa variables
	this->demo.enabled = demo;
	this->numPlayers = numPlayers;
	this->currentStage = currentStage;
	lastStageReached = currentStage;
	if (numPlayers == 1)
	{ // Si solo juega un jugador, permite jugar tanto con teclado como con mando
		onePlayerControl = options->input[0].deviceType;
		options->input[0].deviceType = INPUT_USE_ANY;
	}
	difficulty = options->difficulty;

	// Crea los objetos
	fade = new Fade(renderer);
	eventHandler = new SDL_Event();

	// Carga los recursos
	loadMedia();

	clouds1A = new MovingSprite(0, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, gameCloudsTexture, renderer);
	clouds1B = new MovingSprite(256, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, gameCloudsTexture, renderer);
	clouds2A = new MovingSprite(0, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, gameCloudsTexture, renderer);
	clouds2B = new MovingSprite(256, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, gameCloudsTexture, renderer);

	n1000Sprite = new SmartSprite(gameTextTexture, renderer);
	n2500Sprite = new SmartSprite(gameTextTexture, renderer);
	n5000Sprite = new SmartSprite(gameTextTexture, renderer);

	buildingsSprite = new Sprite(0, 0, 256, 160, gameBuildingsTexture, renderer);

	skyColorsSprite = new Sprite(0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT, gameSkyColorsTexture, renderer);
	grassSprite = new Sprite(0, 0, 256, 6, gameGrassTexture, renderer);
	powerMeterSprite = new Sprite(PLAY_AREA_CENTER_X - 20, 170, 40, 7, gamePowerMeterTexture, renderer);
	gameOverSprite = new Sprite(16, 80, 128, 96, gameOverTexture, renderer);
	gameOverEndSprite = new Sprite(PLAY_AREA_CENTER_X - gameOverEndTexture->getWidth() / 2, 80, 128, 96, gameOverEndTexture, renderer);

	// Inicializa las variables necesarias para la sección 'Game'
	init();
}

Game::~Game()
{
	saveScoreFile();
	sendOnlineScore();
	saveDemoFile();

	// Restaura el metodo de control
	if (numPlayers == 1)
	{
		options->input[0].deviceType = onePlayerControl;
	}

	// Elimina todos los objetos contenidos en vectores
	deleteAllVectorObjects();

	bulletTexture->unload();
	delete bulletTexture;

	gameBuildingsTexture->unload();
	delete gameBuildingsTexture;

	gameCloudsTexture->unload();
	delete gameCloudsTexture;

	gameGrassTexture->unload();
	delete gameGrassTexture;

	gamePowerMeterTexture->unload();
	delete gamePowerMeterTexture;

	gameSkyColorsTexture->unload();
	delete gameSkyColorsTexture;

	gameTextTexture->unload();
	delete gameTextTexture;

	gameOverTexture->unload();
	delete gameOverTexture;

	gameOverEndTexture->unload();
	delete gameOverEndTexture;

	// Animaciones
	for (auto animation : playerAnimations)
	{
		delete animation;
	}
	playerAnimations.clear();

	for (auto animation : balloonAnimations)
	{
		delete animation;
	}
	balloonAnimations.clear();

	for (auto animation : itemAnimations)
	{
		delete animation;
	}
	itemAnimations.clear();

	// Texturas
	for (auto texture : player1Textures)
	{
		texture->unload();
		delete texture;
	}
	player1Textures.clear();

	for (auto texture : player2Textures)
	{
		texture->unload();
		delete texture;
	}
	player2Textures.clear();

	for (auto texture : itemTextures)
	{
		texture->unload();
		delete texture;
	}
	itemTextures.clear();

	for (auto texture : balloonTextures)
	{
		texture->unload();
		delete texture;
	}
	balloonTextures.clear();

	delete text;
	delete textBig;
	delete textScoreBoard;
	delete textNokia2;
	delete textNokiaBig2;
	delete gameOverMenu;
	delete pauseMenu;
	delete fade;
	delete eventHandler;
	delete clouds1A;
	delete clouds1B;
	delete clouds2A;
	delete clouds2B;
	delete n1000Sprite;
	delete n2500Sprite;
	delete n5000Sprite;
	delete buildingsSprite;

	delete skyColorsSprite;
	delete grassSprite;
	delete powerMeterSprite;
	delete gameOverSprite;
	delete gameOverEndSprite;

	JA_DeleteSound(balloonSound);
	JA_DeleteSound(bulletSound);
	JA_DeleteSound(playerCollisionSound);
	JA_DeleteSound(hiScoreSound);
	JA_DeleteSound(itemDropSound);
	JA_DeleteSound(itemPickUpSound);
	JA_DeleteSound(coffeeOutSound);
	JA_DeleteSound(stageChangeSound);
	JA_DeleteSound(bubble1Sound);
	JA_DeleteSound(bubble2Sound);
	JA_DeleteSound(bubble3Sound);
	JA_DeleteSound(bubble4Sound);
	JA_DeleteSound(clockSound);
	JA_DeleteSound(powerBallSound);
	JA_DeleteSound(coffeeMachineSound);

	JA_DeleteMusic(gameMusic);
}

// Inicializa las variables necesarias para la sección 'Game'
void Game::init()
{
	ticks = 0;
	ticksSpeed = 15;

	// Elimina qualquier jugador que hubiese antes de crear los nuevos
	for (auto player : players)
	{
		delete player;
	};
	players.clear();

	// Crea los jugadores
	if (numPlayers == 1)
	{
		Player *player = new Player(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, renderer, playerTextures[options->playerSelected], playerAnimations);
		players.push_back(player);
	}

	else if (numPlayers == 2)
	{
		Player *player1 = new Player((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((0 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, renderer, playerTextures[0], playerAnimations);
		Player *player2 = new Player((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((1 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, renderer, playerTextures[1], playerAnimations);
		players.push_back(player1);
		players.push_back(player2);
	}

	// Inicializa las variables
	switch (difficulty)
	{
	case DIFFICULTY_EASY:
		defaultEnemySpeed = BALLOON_SPEED_1;
		difficultyScoreMultiplier = 0.5f;
		difficultyColor = {75, 105, 47};
		pauseMenu->setSelectorColor(difficultyColor, 255);
		gameOverMenu->setSelectorColor(difficultyColor, 255);
		break;

	case DIFFICULTY_NORMAL:
		defaultEnemySpeed = BALLOON_SPEED_1;
		difficultyScoreMultiplier = 1.0f;
		difficultyColor = {255, 122, 0};
		pauseMenu->setSelectorColor(difficultyColor, 255);
		gameOverMenu->setSelectorColor(difficultyColor, 255);
		break;

	case DIFFICULTY_HARD:
		defaultEnemySpeed = BALLOON_SPEED_5;
		difficultyScoreMultiplier = 1.5f;
		difficultyColor = {118, 66, 138};
		pauseMenu->setSelectorColor(difficultyColor, 255);
		gameOverMenu->setSelectorColor(difficultyColor, 255);
		break;

	default:
		break;
	}

	gameCompleted = false;
	gameCompletedCounter = 0;
	section->name = SECTION_PROG_GAME;
	section->subsection = SUBSECTION_GAME_PLAY_1P;
	menaceCurrent = 0;
	menaceThreshold = 0;
	hiScoreAchieved = false;
	stageBitmapCounter = STAGE_COUNTER;
	deathCounter = DEATH_COUNTER;
	timeStopped = false;
	timeStoppedCounter = 0;
	counter = 0;
	lastEnemyDeploy = 0;
	enemyDeployCounter = 0;
	enemySpeed = defaultEnemySpeed;
	effect.flash = false;
	effect.shake = false;
	effect.shakeCounter = SHAKE_COUNTER;
	helper.needCoffee = false;
	helper.needCoffeeMachine = false;
	helper.needPowerBall = false;
	helper.counter = HELP_COUNTER;
	helper.itemPoints1Odds = ITEM_POINTS_1_DISK_ODDS;
	helper.itemPoints2Odds = ITEM_POINTS_2_GAVINA_ODDS;
	helper.itemPoints3Odds = ITEM_POINTS_3_PACMAR_ODDS;
	helper.itemClockOdds = ITEM_CLOCK_ODDS;
	helper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
	helper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
	powerBallEnabled = false;
	powerBallCounter = 0;
	coffeeMachineEnabled = false;
	pauseCounter = 0;
	leavingPauseMenu = false;

	if (demo.enabled)
	{
		const int num = rand() % 2;
		if (num == 0)
		{
			balloonsPopped = 1000;
			currentStage = 3;
		}
		else
		{
			balloonsPopped = 1800;
			currentStage = 6;
		}
	}

	initPaths();
	initEnemyFormations();
	initEnemyPools();
	initGameStages();

	// Mas variables
	balloonsPopped = 0;
	for (int i = 0; i < currentStage; ++i)
	{
		balloonsPopped += stage[i].powerToComplete;
	}

	totalPowerToCompleteGame = 0;
	for (int i = 0; i < 10; ++i)
	{
		totalPowerToCompleteGame += stage[i].powerToComplete;
	}

	// Modo demo
	demo.recording = false;
	demo.counter = 0;

	// Inicializa el objeto para el fundido
	fade->init(0x27, 0x27, 0x36);

	// Sprites
	clouds1A->setSpriteClip(0, 0, 256, 52);
	clouds1B->setSpriteClip(0, 0, 256, 52);
	clouds2A->setSpriteClip(0, 52, 256, 32);
	clouds2B->setSpriteClip(0, 52, 256, 32);

	grassSprite->setPosY(154);
	powerMeterSprite->setSpriteClip(0, 0, 40, 7);

	// Con los globos creados, calcula el nivel de amenaza
	evaluateAndSetMenace();

	// Inicializa el bitmap de 1000 puntos
	n1000Sprite->setPosX(0);
	n1000Sprite->setPosY(0);
	n1000Sprite->setWidth(26);
	n1000Sprite->setHeight(9);
	n1000Sprite->setVelX(0.0f);
	n1000Sprite->setVelY(-0.5f);
	n1000Sprite->setAccelX(0.0f);
	n1000Sprite->setAccelY(-0.1f);
	n1000Sprite->setSpriteClip(0, 0, 26, 9);
	n1000Sprite->setEnabled(false);
	n1000Sprite->setEnabledCounter(0);
	n1000Sprite->setDestX(0);
	n1000Sprite->setDestY(0);

	// Inicializa el bitmap de 2500 puntos
	n2500Sprite->setPosX(0);
	n2500Sprite->setPosY(0);
	n2500Sprite->setWidth(28);
	n2500Sprite->setHeight(9);
	n2500Sprite->setVelX(0.0f);
	n2500Sprite->setVelY(-0.5f);
	n2500Sprite->setAccelX(0.0f);
	n2500Sprite->setAccelY(-0.1f);
	n2500Sprite->setSpriteClip(26, 0, 28, 9);
	n2500Sprite->setEnabled(false);
	n2500Sprite->setEnabledCounter(0);
	n2500Sprite->setDestX(0);
	n2500Sprite->setDestY(0);

	// Inicializa el bitmap de 5000 puntos
	n5000Sprite->setPosX(0);
	n5000Sprite->setPosY(0);
	n5000Sprite->setWidth(28);
	n5000Sprite->setHeight(9);
	n5000Sprite->setVelX(0.0f);
	n5000Sprite->setVelY(-0.5f);
	n5000Sprite->setAccelX(0.0f);
	n5000Sprite->setAccelY(-0.1f);
	n5000Sprite->setSpriteClip(54, 0, 28, 9);
	n5000Sprite->setEnabled(false);
	n5000Sprite->setEnabledCounter(0);
	n5000Sprite->setDestX(0);
	n5000Sprite->setDestY(0);

	// Los fondos
	skyColorsRect[0] = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
	skyColorsRect[1] = {256, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
	skyColorsRect[2] = {0, 192, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
	skyColorsRect[3] = {256, 192, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
}

// Carga los recursos necesarios para la sección 'Game'
void Game::loadMedia()
{
	if (options->console)
	{
		std::cout << std::endl
				  << "** LOADING RESOURCES FOR GAME SECTION" << std::endl;
	}

	// Carga ficheros
	loadScoreFile();
	loadDemoFile();

	// Texturas
	bulletTexture = new Texture(renderer, asset->get("bullet.png"));
	gameBuildingsTexture = new Texture(renderer, asset->get("game_buildings.png"));
	gameCloudsTexture = new Texture(renderer, asset->get("game_clouds.png"));
	gameGrassTexture = new Texture(renderer, asset->get("game_grass.png"));
	gamePowerMeterTexture = new Texture(renderer, asset->get("game_power_meter.png"));
	gameSkyColorsTexture = new Texture(renderer, asset->get("game_sky_colors.png"));
	gameTextTexture = new Texture(renderer, asset->get("game_text.png"));
	gameOverTexture = new Texture(renderer, asset->get("menu_game_over.png"));
	gameOverEndTexture = new Texture(renderer, asset->get("menu_game_over_end.png"));

	// Texturas - Globos
	Texture *balloon1Texture = new Texture(renderer, asset->get("balloon1.png"));
	balloonTextures.push_back(balloon1Texture);

	Texture *balloon2Texture = new Texture(renderer, asset->get("balloon2.png"));
	balloonTextures.push_back(balloon2Texture);

	Texture *balloon3Texture = new Texture(renderer, asset->get("balloon3.png"));
	balloonTextures.push_back(balloon3Texture);

	Texture *balloon4Texture = new Texture(renderer, asset->get("balloon4.png"));
	balloonTextures.push_back(balloon4Texture);

	// Texturas - Items
	Texture *item1 = new Texture(renderer, asset->get("item_points1_disk.png"));
	itemTextures.push_back(item1);

	Texture *item2 = new Texture(renderer, asset->get("item_points2_gavina.png"));
	itemTextures.push_back(item2);

	Texture *item3 = new Texture(renderer, asset->get("item_points3_pacmar.png"));
	itemTextures.push_back(item3);

	Texture *item4 = new Texture(renderer, asset->get("item_clock.png"));
	itemTextures.push_back(item4);

	Texture *item5 = new Texture(renderer, asset->get("item_coffee.png"));
	itemTextures.push_back(item5);

	Texture *item6 = new Texture(renderer, asset->get("item_coffee_machine.png"));
	itemTextures.push_back(item6);

	// Texturas - Player1
	Texture *player1Head = new Texture(renderer, asset->get("player_bal1_head.png"));
	player1Textures.push_back(player1Head);

	Texture *player1Body = new Texture(renderer, asset->get("player_bal1_body.png"));
	player1Textures.push_back(player1Body);

	Texture *player1Legs = new Texture(renderer, asset->get("player_bal1_legs.png"));
	player1Textures.push_back(player1Legs);

	Texture *player1Death = new Texture(renderer, asset->get("player_bal1_death.png"));
	player1Textures.push_back(player1Death);

	Texture *player1Fire = new Texture(renderer, asset->get("player_bal1_fire.png"));
	player1Textures.push_back(player1Fire);

	playerTextures.push_back(player1Textures);

	// Texturas - Player2
	Texture *player2Head = new Texture(renderer, asset->get("player_arounder_head.png"));
	player2Textures.push_back(player2Head);

	Texture *player2Body = new Texture(renderer, asset->get("player_arounder_body.png"));
	player2Textures.push_back(player2Body);

	Texture *player2Legs = new Texture(renderer, asset->get("player_arounder_legs.png"));
	player2Textures.push_back(player2Legs);

	Texture *player2Death = new Texture(renderer, asset->get("player_arounder_death.png"));
	player2Textures.push_back(player2Death);

	Texture *player2Fire = new Texture(renderer, asset->get("player_arounder_fire.png"));
	player2Textures.push_back(player2Fire);

	playerTextures.push_back(player2Textures);

	// Animaciones -- Jugador
	std::vector<std::string> *playerHeadAnimation = new std::vector<std::string>;
	loadAnimations(asset->get("player_head.ani"), playerHeadAnimation);
	playerAnimations.push_back(playerHeadAnimation);

	std::vector<std::string> *playerBodyAnimation = new std::vector<std::string>;
	loadAnimations(asset->get("player_body.ani"), playerBodyAnimation);
	playerAnimations.push_back(playerBodyAnimation);

	std::vector<std::string> *playerLegsAnimation = new std::vector<std::string>;
	loadAnimations(asset->get("player_legs.ani"), playerLegsAnimation);
	playerAnimations.push_back(playerLegsAnimation);

	std::vector<std::string> *playerDeathAnimation = new std::vector<std::string>;
	loadAnimations(asset->get("player_death.ani"), playerDeathAnimation);
	playerAnimations.push_back(playerDeathAnimation);

	std::vector<std::string> *playerFireAnimation = new std::vector<std::string>;
	loadAnimations(asset->get("player_fire.ani"), playerFireAnimation);
	playerAnimations.push_back(playerFireAnimation);

	// Animaciones -- Globos
	std::vector<std::string> *balloon1Animation = new std::vector<std::string>;
	loadAnimations(asset->get("balloon1.ani"), balloon1Animation);
	balloonAnimations.push_back(balloon1Animation);

	std::vector<std::string> *balloon2Animation = new std::vector<std::string>;
	loadAnimations(asset->get("balloon2.ani"), balloon2Animation);
	balloonAnimations.push_back(balloon2Animation);

	std::vector<std::string> *balloon3Animation = new std::vector<std::string>;
	loadAnimations(asset->get("balloon3.ani"), balloon3Animation);
	balloonAnimations.push_back(balloon3Animation);

	std::vector<std::string> *balloon4Animation = new std::vector<std::string>;
	loadAnimations(asset->get("balloon4.ani"), balloon4Animation);
	balloonAnimations.push_back(balloon4Animation);

	// Animaciones -- Items
	std::vector<std::string> *item1Animation = new std::vector<std::string>;
	loadAnimations(asset->get("item_points1_disk.ani"), item1Animation);
	itemAnimations.push_back(item1Animation);

	std::vector<std::string> *item2Animation = new std::vector<std::string>;
	loadAnimations(asset->get("item_points2_gavina.ani"), item2Animation);
	itemAnimations.push_back(item2Animation);

	std::vector<std::string> *item3Animation = new std::vector<std::string>;
	loadAnimations(asset->get("item_points3_pacmar.ani"), item3Animation);
	itemAnimations.push_back(item3Animation);

	std::vector<std::string> *item4Animation = new std::vector<std::string>;
	loadAnimations(asset->get("item_clock.ani"), item4Animation);
	itemAnimations.push_back(item4Animation);

	std::vector<std::string> *item5Animation = new std::vector<std::string>;
	loadAnimations(asset->get("item_coffee.ani"), item5Animation);
	itemAnimations.push_back(item5Animation);

	std::vector<std::string> *item6Animation = new std::vector<std::string>;
	loadAnimations(asset->get("item_coffee_machine.ani"), item6Animation);
	itemAnimations.push_back(item6Animation);

	// Texto
	text = new Text(asset->get("smb2.png"), asset->get("smb2.txt"), renderer);
	textScoreBoard = new Text(asset->get("8bithud.png"), asset->get("8bithud.txt"), renderer);
	textBig = new Text(asset->get("smb2_big.png"), asset->get("smb2_big.txt"), renderer);
	textNokia2 = new Text(asset->get("nokia2.png"), asset->get("nokia2.txt"), renderer);
	textNokiaBig2 = new Text(asset->get("nokia_big2.png"), asset->get("nokia_big2.txt"), renderer);

	// Menus
	gameOverMenu = new Menu(renderer, asset, input, asset->get("gameover.men"));
	gameOverMenu->setItemCaption(0, lang->getText(48));
	gameOverMenu->setItemCaption(1, lang->getText(49));
	const int w = text->getCharacterSize() * lang->getText(45).length();
	gameOverMenu->setRectSize(w, 0);
	gameOverMenu->centerMenuOnX(199);
	pauseMenu = new Menu(renderer, asset, input, asset->get("pause.men"));
	pauseMenu->setItemCaption(0, lang->getText(41));
	pauseMenu->setItemCaption(1, lang->getText(46));
	pauseMenu->setItemCaption(2, lang->getText(47));

	// Sonidos
	balloonSound = JA_LoadSound(asset->get("balloon.wav").c_str());
	bubble1Sound = JA_LoadSound(asset->get("bubble1.wav").c_str());
	bubble2Sound = JA_LoadSound(asset->get("bubble2.wav").c_str());
	bubble3Sound = JA_LoadSound(asset->get("bubble3.wav").c_str());
	bubble4Sound = JA_LoadSound(asset->get("bubble4.wav").c_str());
	bulletSound = JA_LoadSound(asset->get("bullet.wav").c_str());
	clockSound = JA_LoadSound(asset->get("clock.wav").c_str());
	coffeeOutSound = JA_LoadSound(asset->get("coffeeout.wav").c_str());
	hiScoreSound = JA_LoadSound(asset->get("hiscore.wav").c_str());
	itemDropSound = JA_LoadSound(asset->get("itemdrop.wav").c_str());
	itemPickUpSound = JA_LoadSound(asset->get("itempickup.wav").c_str());
	playerCollisionSound = JA_LoadSound(asset->get("player_collision.wav").c_str());
	powerBallSound = JA_LoadSound(asset->get("powerball.wav").c_str());
	stageChangeSound = JA_LoadSound(asset->get("stage_change.wav").c_str());
	coffeeMachineSound = JA_LoadSound(asset->get("title.wav").c_str());

	// Musicas
	gameMusic = JA_LoadMusic(asset->get("playing.ogg").c_str());

	if (options->console)
	{
		std::cout << "** RESOURCES FOR GAME SECTION LOADED" << std::endl
				  << std::endl;
	}
}

// Carga el fichero de puntos
bool Game::loadScoreFile()
{
	// Indicador de éxito en la carga
	bool success = true;
	const std::string p = asset->get("score.bin");
	const std::string filename = p.substr(p.find_last_of("\\/") + 1);
	SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b");

	// El fichero no existe
	if (file == nullptr)
	{
		if (options->console)
		{
			std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
		}

		// Creamos el fichero para escritura
		file = SDL_RWFromFile(p.c_str(), "w+b");
		if (file != nullptr)
		{
			if (options->console)
			{
				std::cout << "New file (" << filename.c_str() << ") created!" << std::endl;
			}

			// Inicializamos los datos
			for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
			{
				scoreDataFile[i] = 0;
				SDL_RWwrite(file, &scoreDataFile[i], sizeof(Uint32), 1);
			}

			// Cerramos el fichero
			SDL_RWclose(file);
		}
		else
		{
			if (options->console)
			{
				std::cout << "Error: Unable to create file " << filename.c_str() << std::endl;
			}
			success = false;
		}
	}
	// El fichero existe
	else
	{
		// Cargamos los datos
		if (options->console)
		{
			std::cout << "Reading file " << filename.c_str() << std::endl;
		}
		for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
			SDL_RWread(file, &scoreDataFile[i], sizeof(Uint32), 1);

		// Cierra el fichero
		SDL_RWclose(file);
	}

	// Establece el valor de la máxima puntuación a partir del vector con los datos
	if (scoreDataFile[0] == 0)
	{
		hiScore = 10000;
	}
	// Comprueba el checksum para ver si se ha modificado el fichero
	else if (scoreDataFile[0] % 43 == scoreDataFile[1])
	{
		hiScore = scoreDataFile[0];
	}
	else
	{
		hiScore = 10000;
	}

	return success;
}

// Carga el fichero de datos para la demo
bool Game::loadDemoFile()
{
	// Indicador de éxito en la carga
	bool success = true;
	const std::string p = asset->get("demo.bin");
	const std::string filename = p.substr(p.find_last_of("\\/") + 1);
	SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b");

	// El fichero no existe
	if (file == nullptr)
	{
		if (options->console)
		{
			std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
		}

		// Creamos el fichero para escritura
		file = SDL_RWFromFile(p.c_str(), "w+b");
		if (file != nullptr)
		{
			if (options->console)
			{
				std::cout << "New file (" << filename.c_str() << ") created!" << std::endl;
			}

			// Inicializamos los datos
			for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
			{
				demo.keys.left = 0;
				demo.keys.right = 0;
				demo.keys.noInput = 0;
				demo.keys.fire = 0;
				demo.keys.fireLeft = 0;
				demo.keys.fireRight = 0;
				demo.dataFile[i] = demo.keys;
				SDL_RWwrite(file, &demo.dataFile[i], sizeof(demoKeys_t), 1);
			}

			// Cerramos el fichero
			SDL_RWclose(file);
		}
		else
		{
			if (options->console)
			{
				std::cout << "Error: Unable to create file " << filename.c_str() << std::endl;
			}
			success = false;
		}
	}
	// El fichero existe
	else
	{
		// Cargamos los datos
		if (options->console)
		{
			std::cout << "Reading file " << filename.c_str() << std::endl;
		}
		for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
			SDL_RWread(file, &demo.dataFile[i], sizeof(demoKeys_t), 1);

		// Cierra el fichero
		SDL_RWclose(file);
	}

	return success;
}

// Guarda el fichero de puntos
bool Game::saveScoreFile()
{
	bool success = true;
	const std::string p = asset->get("score.bin");
	const std::string filename = p.substr(p.find_last_of("\\/") + 1);
	SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b");
	if (file != nullptr)
	{
		// Guardamos los datos
		for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
		{
			SDL_RWwrite(file, &scoreDataFile[i], sizeof(Uint32), 1);
		}

		if (options->console)
		{
			std::cout << "Writing file " << filename.c_str() << std::endl;
		}

		// Cerramos el fichero
		SDL_RWclose(file);
	}
	else
	{
		if (options->console)
		{
			std::cout << "Error: Unable to save " << filename.c_str() << " file! " << SDL_GetError() << std::endl;
		}
	}
	return success;
}

// Sube la puntuación online
bool Game::sendOnlineScore()
{
	if (!options->online.enabled)
	{
		return true;
	}

	if (demo.enabled)
	{
		return true;
	}

	const int score = players[0]->getScore();
	if (score <= options->online.score)
	{
		return true;
	}

	if (jscore::updateUserPoints(options->online.gameID, options->online.jailerID, score))
	{
		options->online.score = score;
		screen->showNotification(lang->getText(86) + std::to_string(score), "", 2);
		return true;
	}
	else
	{
		screen->showNotification(lang->getText(86), lang->getText(87));
		return false;
	}
}

// Guarda el fichero de datos para la demo
bool Game::saveDemoFile()
{
	bool success = true;
	const std::string p = asset->get("demo.bin");
	const std::string filename = p.substr(p.find_last_of("\\/") + 1);
	if (demo.recording)
	{
		SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b");
		if (file != nullptr)
		{
			// Guardamos los datos
			for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
			{
				SDL_RWwrite(file, &demo.dataFile[i], sizeof(demoKeys_t), 1);
			}

			if (options->console)
			{
				std::cout << "Writing file " << filename.c_str() << std::endl;
			}

			// Cerramos el fichero
			SDL_RWclose(file);
		}
		else
		{
			if (options->console)
			{
				std::cout << "Error: Unable to save " << filename.c_str() << " file! " << SDL_GetError() << std::endl;
			}
		}
	}
	return success;
}

// Inicializa las formaciones enemigas
void Game::initEnemyFormations()
{
	const int y4 = (PLAY_AREA_TOP - BLOCK);
	const int x4_0 = PLAY_AREA_LEFT;
	const int x4_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_4;

	const int y3 = (PLAY_AREA_TOP - BLOCK);
	const int x3_0 = PLAY_AREA_LEFT;
	const int x3_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_3;

	const int y2 = (PLAY_AREA_TOP - BLOCK);
	const int x2_0 = PLAY_AREA_LEFT;
	const int x2_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_2;

	const int y1 = (PLAY_AREA_TOP - BLOCK);
	const int x1_0 = PLAY_AREA_LEFT;
	const int x1_50 = PLAY_AREA_CENTER_X - (BALLOON_WIDTH_1 / 2);
	const int x1_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_1;

	// Inicializa a cero las variables
	for (int i = 0; i < NUMBER_OF_ENEMY_FORMATIONS; i++)
	{
		enemyFormation[i].numberOfEnemies = 0;
		for (int j = 0; j < MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION; j++)
		{
			enemyFormation[i].init[j].x = 0;
			enemyFormation[i].init[j].y = 0;
			enemyFormation[i].init[j].velX = 0;
			enemyFormation[i].init[j].kind = 0;
			enemyFormation[i].init[j].creationCounter = 0;
		}
	}

	const Uint16 creationTime = 300;
	int incX = 0;
	Uint8 incTime = 0;
	Uint8 j = 0;

	// #00 - Dos enemigos BALLOON4 uno a cada extremo
	j = 0;
	enemyFormation[j].numberOfEnemies = 2;
	incX = x4_100;
	incTime = 0;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x4_0 + (i * incX);
		enemyFormation[j].init[i].y = y4;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
		enemyFormation[j].init[i].kind = BALLOON_4;
		enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
	}

	// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
	j = 1;
	enemyFormation[j].numberOfEnemies = 2;
	incX = PLAY_AREA_CENTER_X;
	incTime = 0;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = PLAY_AREA_CENTER_FIRST_QUARTER_X - (BALLOON_WIDTH_4 / 2) + (i * incX);
		enemyFormation[j].init[i].y = y4;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
		enemyFormation[j].init[i].kind = BALLOON_4;
		enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
	}

	// #02 - Cuatro enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
	j = 2;
	enemyFormation[j].numberOfEnemies = 4;
	incX = BALLOON_WIDTH_2 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x2_0 + (i * incX);
		enemyFormation[j].init[i].y = y2;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_2;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #03 - Cuatro enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
	j = 3;
	enemyFormation[j].numberOfEnemies = 4;
	incX = BALLOON_WIDTH_2 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x2_100 - (i * incX);
		enemyFormation[j].init[i].y = y2;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_2;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
	j = 4;
	enemyFormation[j].numberOfEnemies = 3;
	incX = BALLOON_WIDTH_3 * 2;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_0 + (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
	j = 5;
	enemyFormation[j].numberOfEnemies = 3;
	incX = BALLOON_WIDTH_3 * 2;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_100 - (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
	j = 6;
	enemyFormation[j].numberOfEnemies = 3;
	incX = BALLOON_WIDTH_3 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_0 + (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
	j = 7;
	enemyFormation[j].numberOfEnemies = 3;
	incX = BALLOON_WIDTH_3 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_100 - (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
	j = 8;
	enemyFormation[j].numberOfEnemies = 6;
	incX = BALLOON_WIDTH_1 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x1_0 + (i * incX);
		enemyFormation[j].init[i].y = 13;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_1;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
	j = 9;
	enemyFormation[j].numberOfEnemies = 6;
	incX = BALLOON_WIDTH_1 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x1_100 - (i * incX);
		enemyFormation[j].init[i].y = 13;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_1;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda
	j = 10;
	enemyFormation[j].numberOfEnemies = 3;
	incX = BALLOON_WIDTH_4 + 1;
	incTime = 15;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x4_0 + (i * incX);
		enemyFormation[j].init[i].y = y4;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_4;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #11 - Tres enemigos BALLOON4 seguidos desde la derecha
	j = 11;
	enemyFormation[j].numberOfEnemies = 3;
	incX = BALLOON_WIDTH_4 + 1;
	incTime = 15;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x4_100 - (i * incX);
		enemyFormation[j].init[i].y = y4;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_4;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #12 - Seis enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
	j = 12;
	enemyFormation[j].numberOfEnemies = 6;
	incX = BALLOON_WIDTH_2 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x2_0 + (i * incX);
		enemyFormation[j].init[i].y = y2;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_2;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #13 - Seis enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
	j = 13;
	enemyFormation[j].numberOfEnemies = 6;
	incX = BALLOON_WIDTH_2 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x2_100 - (i * incX);
		enemyFormation[j].init[i].y = y2;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_2;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
	j = 14;
	enemyFormation[j].numberOfEnemies = 5;
	incX = BALLOON_WIDTH_3 * 2;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_0 + (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
	j = 15;
	enemyFormation[j].numberOfEnemies = 5;
	incX = BALLOON_WIDTH_3 * 2;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_100 - (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
	j = 16;
	enemyFormation[j].numberOfEnemies = 5;
	incX = BALLOON_WIDTH_3 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_0 + (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
	j = 17;
	enemyFormation[j].numberOfEnemies = 5;
	incX = BALLOON_WIDTH_3 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x3_100 - (i * incX);
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_3;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
	j = 18;
	enemyFormation[j].numberOfEnemies = 12;
	incX = BALLOON_WIDTH_1 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x1_0 + (i * incX);
		enemyFormation[j].init[i].y = y1;
		enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		enemyFormation[j].init[i].kind = BALLOON_1;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
	j = 19;
	enemyFormation[j].numberOfEnemies = 12;
	incX = BALLOON_WIDTH_1 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		enemyFormation[j].init[i].x = x1_100 - (i * incX);
		enemyFormation[j].init[i].y = y1;
		enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		enemyFormation[j].init[i].kind = BALLOON_1;
		enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
	}

	// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simetricos
	j = 20;
	enemyFormation[j].numberOfEnemies = 4;
	incX = BALLOON_WIDTH_4 + 1;
	incTime = 0;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		Uint8 half = enemyFormation[j].numberOfEnemies / 2;
		if (i < half)
		{
			enemyFormation[j].init[i].x = x4_0 + (i * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
		}
		else
		{
			enemyFormation[j].init[i].x = x4_100 - ((i - half) * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
		}
		enemyFormation[j].init[i].y = y4;
		enemyFormation[j].init[i].kind = BALLOON_4;
		enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
	}

	// #21 - Diez enemigos BALLOON2 uno detras del otro. Izquierda/derecha. Simetricos
	j = 21;
	enemyFormation[j].numberOfEnemies = 10;
	incX = BALLOON_WIDTH_2 + 1;
	incTime = 3;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		Uint8 half = enemyFormation[j].numberOfEnemies / 2;
		if (i < half)
		{
			enemyFormation[j].init[i].x = x2_0 + (i * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
		}
		else
		{
			enemyFormation[j].init[i].x = x2_100 - ((i - half) * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
		}
		enemyFormation[j].init[i].y = y2;
		enemyFormation[j].init[i].kind = BALLOON_2;
	}

	// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simetricos
	j = 22;
	enemyFormation[j].numberOfEnemies = 10;
	incX = BALLOON_WIDTH_3 * 2;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		Uint8 half = enemyFormation[j].numberOfEnemies / 2;
		if (i < half)
		{
			enemyFormation[j].init[i].x = x3_0 + (i * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
		}
		else
		{
			enemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
		}
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].kind = BALLOON_3;
	}

	// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simetricos
	j = 23;
	enemyFormation[j].numberOfEnemies = 10;
	incX = BALLOON_WIDTH_3 + 1;
	incTime = 10;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		Uint8 half = enemyFormation[j].numberOfEnemies / 2;
		if (i < half)
		{
			enemyFormation[j].init[i].x = x3_0 + (i * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
		}
		else
		{
			enemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
			enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
		}
		enemyFormation[j].init[i].y = y3;
		enemyFormation[j].init[i].kind = BALLOON_3;
	}

	// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simetricos
	j = 24;
	enemyFormation[j].numberOfEnemies = 30;
	incX = 0;
	incTime = 5;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		Uint8 half = enemyFormation[j].numberOfEnemies / 2;
		if (i < half)
		{
			enemyFormation[j].init[i].x = x1_50;
			enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * i);
		}
		else
		{
			enemyFormation[j].init[i].x = x1_50;
			enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * (i - half));
		}
		enemyFormation[j].init[i].y = y1;
		enemyFormation[j].init[i].kind = BALLOON_1;
	}

	// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simetricos
	j = 25;
	enemyFormation[j].numberOfEnemies = 30;
	incX = BALLOON_WIDTH_1 + 1;
	incTime = 5;
	for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
	{
		Uint8 half = enemyFormation[j].numberOfEnemies / 2;
		if (i < half)
		{
			enemyFormation[j].init[i].x = x1_50 + 20;
			enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
		}
		else
		{
			enemyFormation[j].init[i].x = x1_50 - 20;
			enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
			enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
		}
		enemyFormation[j].init[i].y = y1;
		enemyFormation[j].init[i].kind = BALLOON_1;
	}

	// Crea las mismas formaciones pero con hexagonos a partir de la posición 50 del vector
	for (int k = 0; k < j + 1; k++)
	{
		enemyFormation[k + 50].numberOfEnemies = enemyFormation[k].numberOfEnemies;
		for (int i = 0; i < enemyFormation[k + 50].numberOfEnemies; i++)
		{
			enemyFormation[k + 50].init[i].x = enemyFormation[k].init[i].x;
			enemyFormation[k + 50].init[i].y = enemyFormation[k].init[i].y;
			enemyFormation[k + 50].init[i].velX = enemyFormation[k].init[i].velX;
			enemyFormation[k + 50].init[i].creationCounter = enemyFormation[k].init[i].creationCounter;
			enemyFormation[k + 50].init[i].kind = enemyFormation[k].init[i].kind + 4;
		}
	}

	// TEST
	enemyFormation[99].numberOfEnemies = 4;

	enemyFormation[99].init[0].x = 10;
	enemyFormation[99].init[0].y = y1;
	enemyFormation[99].init[0].velX = 0;
	enemyFormation[99].init[0].kind = BALLOON_1;
	enemyFormation[99].init[0].creationCounter = 200;

	enemyFormation[99].init[1].x = 50;
	enemyFormation[99].init[1].y = y1;
	enemyFormation[99].init[1].velX = 0;
	enemyFormation[99].init[1].kind = BALLOON_2;
	enemyFormation[99].init[1].creationCounter = 200;

	enemyFormation[99].init[2].x = 90;
	enemyFormation[99].init[2].y = y1;
	enemyFormation[99].init[2].velX = 0;
	enemyFormation[99].init[2].kind = BALLOON_3;
	enemyFormation[99].init[2].creationCounter = 200;

	enemyFormation[99].init[3].x = 140;
	enemyFormation[99].init[3].y = y1;
	enemyFormation[99].init[3].velX = 0;
	enemyFormation[99].init[3].kind = BALLOON_4;
	enemyFormation[99].init[3].creationCounter = 200;
}

// Inicializa los conjuntos de formaciones
void Game::initEnemyPools()
{
	// EnemyPool #0
	enemyPool[0].set[0] = &enemyFormation[0];
	enemyPool[0].set[1] = &enemyFormation[1];
	enemyPool[0].set[2] = &enemyFormation[2];
	enemyPool[0].set[3] = &enemyFormation[3];
	enemyPool[0].set[4] = &enemyFormation[4];
	enemyPool[0].set[5] = &enemyFormation[5];
	enemyPool[0].set[6] = &enemyFormation[6];
	enemyPool[0].set[7] = &enemyFormation[7];
	enemyPool[0].set[8] = &enemyFormation[8];
	enemyPool[0].set[9] = &enemyFormation[9];

	// EnemyPool #1
	enemyPool[1].set[0] = &enemyFormation[10];
	enemyPool[1].set[1] = &enemyFormation[11];
	enemyPool[1].set[2] = &enemyFormation[12];
	enemyPool[1].set[3] = &enemyFormation[13];
	enemyPool[1].set[4] = &enemyFormation[14];
	enemyPool[1].set[5] = &enemyFormation[15];
	enemyPool[1].set[6] = &enemyFormation[16];
	enemyPool[1].set[7] = &enemyFormation[17];
	enemyPool[1].set[8] = &enemyFormation[18];
	enemyPool[1].set[9] = &enemyFormation[19];

	// EnemyPool #2
	enemyPool[2].set[0] = &enemyFormation[0];
	enemyPool[2].set[1] = &enemyFormation[1];
	enemyPool[2].set[2] = &enemyFormation[2];
	enemyPool[2].set[3] = &enemyFormation[3];
	enemyPool[2].set[4] = &enemyFormation[4];
	enemyPool[2].set[5] = &enemyFormation[55];
	enemyPool[2].set[6] = &enemyFormation[56];
	enemyPool[2].set[7] = &enemyFormation[57];
	enemyPool[2].set[8] = &enemyFormation[58];
	enemyPool[2].set[9] = &enemyFormation[59];

	// EnemyPool #3
	enemyPool[3].set[0] = &enemyFormation[50];
	enemyPool[3].set[1] = &enemyFormation[51];
	enemyPool[3].set[2] = &enemyFormation[52];
	enemyPool[3].set[3] = &enemyFormation[53];
	enemyPool[3].set[4] = &enemyFormation[54];
	enemyPool[3].set[5] = &enemyFormation[5];
	enemyPool[3].set[6] = &enemyFormation[6];
	enemyPool[3].set[7] = &enemyFormation[7];
	enemyPool[3].set[8] = &enemyFormation[8];
	enemyPool[3].set[9] = &enemyFormation[9];

	// EnemyPool #4
	enemyPool[4].set[0] = &enemyFormation[60];
	enemyPool[4].set[1] = &enemyFormation[61];
	enemyPool[4].set[2] = &enemyFormation[62];
	enemyPool[4].set[3] = &enemyFormation[63];
	enemyPool[4].set[4] = &enemyFormation[64];
	enemyPool[4].set[5] = &enemyFormation[65];
	enemyPool[4].set[6] = &enemyFormation[66];
	enemyPool[4].set[7] = &enemyFormation[67];
	enemyPool[4].set[8] = &enemyFormation[68];
	enemyPool[4].set[9] = &enemyFormation[69];

	// EnemyPool #5
	enemyPool[5].set[0] = &enemyFormation[10];
	enemyPool[5].set[1] = &enemyFormation[61];
	enemyPool[5].set[2] = &enemyFormation[12];
	enemyPool[5].set[3] = &enemyFormation[63];
	enemyPool[5].set[4] = &enemyFormation[14];
	enemyPool[5].set[5] = &enemyFormation[65];
	enemyPool[5].set[6] = &enemyFormation[16];
	enemyPool[5].set[7] = &enemyFormation[67];
	enemyPool[5].set[8] = &enemyFormation[18];
	enemyPool[5].set[9] = &enemyFormation[69];

	// EnemyPool #6
	enemyPool[6].set[0] = &enemyFormation[60];
	enemyPool[6].set[1] = &enemyFormation[11];
	enemyPool[6].set[2] = &enemyFormation[62];
	enemyPool[6].set[3] = &enemyFormation[13];
	enemyPool[6].set[4] = &enemyFormation[64];
	enemyPool[6].set[5] = &enemyFormation[15];
	enemyPool[6].set[6] = &enemyFormation[66];
	enemyPool[6].set[7] = &enemyFormation[17];
	enemyPool[6].set[8] = &enemyFormation[68];
	enemyPool[6].set[9] = &enemyFormation[19];

	// EnemyPool #7
	enemyPool[7].set[0] = &enemyFormation[20];
	enemyPool[7].set[1] = &enemyFormation[21];
	enemyPool[7].set[2] = &enemyFormation[22];
	enemyPool[7].set[3] = &enemyFormation[23];
	enemyPool[7].set[4] = &enemyFormation[24];
	enemyPool[7].set[5] = &enemyFormation[65];
	enemyPool[7].set[6] = &enemyFormation[66];
	enemyPool[7].set[7] = &enemyFormation[67];
	enemyPool[7].set[8] = &enemyFormation[68];
	enemyPool[7].set[9] = &enemyFormation[69];

	// EnemyPool #8
	enemyPool[8].set[0] = &enemyFormation[70];
	enemyPool[8].set[1] = &enemyFormation[71];
	enemyPool[8].set[2] = &enemyFormation[72];
	enemyPool[8].set[3] = &enemyFormation[73];
	enemyPool[8].set[4] = &enemyFormation[74];
	enemyPool[8].set[5] = &enemyFormation[15];
	enemyPool[8].set[6] = &enemyFormation[16];
	enemyPool[8].set[7] = &enemyFormation[17];
	enemyPool[8].set[8] = &enemyFormation[18];
	enemyPool[8].set[9] = &enemyFormation[19];

	// EnemyPool #9
	enemyPool[9].set[0] = &enemyFormation[20];
	enemyPool[9].set[1] = &enemyFormation[21];
	enemyPool[9].set[2] = &enemyFormation[22];
	enemyPool[9].set[3] = &enemyFormation[23];
	enemyPool[9].set[4] = &enemyFormation[24];
	enemyPool[9].set[5] = &enemyFormation[70];
	enemyPool[9].set[6] = &enemyFormation[71];
	enemyPool[9].set[7] = &enemyFormation[72];
	enemyPool[9].set[8] = &enemyFormation[73];
	enemyPool[9].set[9] = &enemyFormation[74];
}

// Inicializa las fases del juego
void Game::initGameStages()
{
	// STAGE 1
	stage[0].number = 1;
	stage[0].currentPower = 0;
	stage[0].powerToComplete = 200;
	stage[0].minMenace = 7 + (4 * 1);
	stage[0].maxMenace = 7 + (4 * 3);
	stage[0].enemyPool = &enemyPool[0];

	// STAGE 2
	stage[1].number = 2;
	stage[1].currentPower = 0;
	stage[1].powerToComplete = 300;
	stage[1].minMenace = 7 + (4 * 2);
	stage[1].maxMenace = 7 + (4 * 4);
	stage[1].enemyPool = &enemyPool[1];

	// STAGE 3
	stage[2].number = 3;
	stage[2].currentPower = 0;
	stage[2].powerToComplete = 600;
	stage[2].minMenace = 7 + (4 * 3);
	stage[2].maxMenace = 7 + (4 * 5);
	stage[2].enemyPool = &enemyPool[2];

	// STAGE 4
	stage[3].number = 4;
	stage[3].currentPower = 0;
	stage[3].powerToComplete = 600;
	stage[3].minMenace = 7 + (4 * 3);
	stage[3].maxMenace = 7 + (4 * 5);
	stage[3].enemyPool = &enemyPool[3];

	// STAGE 5
	stage[4].number = 5;
	stage[4].currentPower = 0;
	stage[4].powerToComplete = 600;
	stage[4].minMenace = 7 + (4 * 4);
	stage[4].maxMenace = 7 + (4 * 6);
	stage[4].enemyPool = &enemyPool[4];

	// STAGE 6
	stage[5].number = 6;
	stage[5].currentPower = 0;
	stage[5].powerToComplete = 600;
	stage[5].minMenace = 7 + (4 * 4);
	stage[5].maxMenace = 7 + (4 * 6);
	stage[5].enemyPool = &enemyPool[5];

	// STAGE 7
	stage[6].number = 7;
	stage[6].currentPower = 0;
	stage[6].powerToComplete = 650;
	stage[6].minMenace = 7 + (4 * 5);
	stage[6].maxMenace = 7 + (4 * 7);
	stage[6].enemyPool = &enemyPool[6];

	// STAGE 8
	stage[7].number = 8;
	stage[7].currentPower = 0;
	stage[7].powerToComplete = 750;
	stage[7].minMenace = 7 + (4 * 5);
	stage[7].maxMenace = 7 + (4 * 7);
	stage[7].enemyPool = &enemyPool[7];

	// STAGE 9
	stage[8].number = 9;
	stage[8].currentPower = 0;
	stage[8].powerToComplete = 850;
	stage[8].minMenace = 7 + (4 * 6);
	stage[8].maxMenace = 7 + (4 * 8);
	stage[8].enemyPool = &enemyPool[8];

	// STAGE 10
	stage[9].number = 10;
	stage[9].currentPower = 0;
	stage[9].powerToComplete = 950;
	stage[9].minMenace = 7 + (4 * 7);
	stage[9].maxMenace = 7 + (4 * 10);
	stage[9].enemyPool = &enemyPool[9];
}

// Crea una formación de enemigos
void Game::deployEnemyFormation()
{
	// Solo despliega una formación enemiga si ha pasado cierto tiempo desde la última
	if (enemyDeployCounter == 0)
	{

		// En este punto se decide entre crear una powerball o una formación enemiga
		if ((rand() % 100 < 15) && (canPowerBallBeCreated()))
		{
			// Crea una powerball
			createPowerBall();

			// Da un poco de margen para que se creen mas enemigos
			enemyDeployCounter = 50;
		}
		else
		{
			// Decrementa el contador de despliegues enemigos de la PowerBall
			powerBallCounter > 0 ? powerBallCounter-- : powerBallCounter = 0;

			// Elige una formación enemiga la azar
			Uint8 set = (rand() % 10);

			// Evita repetir la ultima formación enemiga desplegada
			if (set == lastEnemyDeploy)
				++set %= 10;

			lastEnemyDeploy = set;

			const Uint8 numEnemies = stage[currentStage].enemyPool->set[set]->numberOfEnemies;
			for (int i = 0; i < numEnemies; ++i)
			{
				createBalloon(stage[currentStage].enemyPool->set[set]->init[i].x,
							  stage[currentStage].enemyPool->set[set]->init[i].y,
							  stage[currentStage].enemyPool->set[set]->init[i].kind,
							  stage[currentStage].enemyPool->set[set]->init[i].velX,
							  enemySpeed,
							  stage[currentStage].enemyPool->set[set]->init[i].creationCounter);
			}

			enemyDeployCounter = 300;
		}
	}
}

// Aumenta el poder de la fase
void Game::increaseStageCurrentPower(Uint8 power)
{
	stage[currentStage].currentPower += power;
}

// Establece el valor de la variable
void Game::setHiScore(Uint32 score)
{
	hiScore = score;
}

// Actualiza el valor de hiScore en caso necesario
void Game::updateHiScore()
{
	// Si la puntuación actual es mayor que la máxima puntuación
	for (auto player : players)
		if (player->getScore() > hiScore)
		{
			// Actualiza la máxima puntuación
			hiScore = player->getScore();

			// Almacena la máxima puntuación en el fichero junto con un checksum
			scoreDataFile[0] = hiScore;
			scoreDataFile[1] = hiScore % 43;

			// Si se supera la máxima puntuación emite sonido
			if (hiScoreAchieved == false)
			{
				hiScoreAchieved = true;
				JA_PlaySound(hiScoreSound);
			}
		}
}

// Transforma un valor numérico en una cadena de 6 cifras
std::string Game::updateScoreText(Uint32 num)
{
	if ((num >= 0) && (num <= 9))
	{
		return ("000000" + std::to_string(num));
	}

	if ((num >= 10) && (num <= 99))
	{
		return ("00000" + std::to_string(num));
	}

	if ((num >= 100) && (num <= 999))
	{
		return ("0000" + std::to_string(num));
	}

	if ((num >= 1000) && (num <= 9999))
	{
		return ("000" + std::to_string(num));
	}

	if ((num >= 010000) && (num <= 99999))
	{
		return ("00" + std::to_string(num));
	}

	if ((num >= 100000) && (num <= 999999))
	{
		return ("0" + std::to_string(num));
	}

	if ((num >= 1000000) && (num <= 9999999))
	{
		return (std::to_string(num));
	}

	return (std::to_string(num));
}

// Pinta el marcador en pantalla usando un objeto texto
void Game::renderScoreBoard()
{
	// Dibuja el fondo del marcador
	if (difficulty == DIFFICULTY_NORMAL)
	{ // Pone el color gris de siempre
		SDL_SetRenderDrawColor(renderer, 46, 63, 71, 255);
	}
	else
	{ // Pinta el fondo del marcador del color de la dificultad
		SDL_SetRenderDrawColor(renderer, difficultyColor.r, difficultyColor.g, difficultyColor.b, 255);
	}
	SDL_Rect rect = {0, 160, 256, 32};
	SDL_RenderFillRect(renderer, &rect);

	// Dibuja la linea que separa el marcador de la zona de juego
	SDL_SetRenderDrawColor(renderer, 13, 26, 43, 255);
	SDL_RenderDrawLine(renderer, 0, 160, 255, 160);

	// Anclas para los elementos
	const int offset1 = 162;
	const int offset2 = offset1 + 7;
	const int offset3 = offset2 + 7;
	const int offset4 = offset3 + 7;

	const int offsetLeft = PLAY_AREA_LEFT + 45;
	const int offsetRight = PLAY_AREA_RIGHT - 45;

	// PLAYER1 - SCORE
	textScoreBoard->writeCentered(offsetLeft, offset1, lang->getText(53));
	textScoreBoard->writeCentered(offsetLeft, offset2, updateScoreText(players[0]->getScore()));

	// PLAYER1 - MULT
	textScoreBoard->writeCentered(offsetLeft, offset3, lang->getText(55));
	textScoreBoard->writeCentered(offsetLeft, offset4, std::to_string(players[0]->getScoreMultiplier()).substr(0, 3));

	if (numPlayers == 2)
	{
		// PLAYER2 - SCORE
		textScoreBoard->writeCentered(offsetRight, offset1, lang->getText(54));
		textScoreBoard->writeCentered(offsetRight, offset2, updateScoreText(players[1]->getScore()));

		// PLAYER2 - MULT
		textScoreBoard->writeCentered(offsetRight, offset3, lang->getText(55));
		textScoreBoard->writeCentered(offsetRight, offset4, std::to_string(players[1]->getScoreMultiplier()).substr(0, 3));
	}
	else
	{
		// PLAYER2 - SCORE
		textScoreBoard->writeCentered(offsetRight, offset1, lang->getText(54));
		textScoreBoard->writeCentered(offsetRight, offset2, "0000000");

		// PLAYER2 - MULT
		textScoreBoard->writeCentered(offsetRight, offset3, lang->getText(55));
		textScoreBoard->writeCentered(offsetRight, offset4, "1.0");
	}

	// STAGE
	textScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset1, lang->getText(57) + std::to_string(stage[currentStage].number));

	// POWERMETER
	powerMeterSprite->setPosY(offset2);
	powerMeterSprite->setSpriteClip(0, 0, 40, 7);
	powerMeterSprite->render();
	const float percent = (stage[currentStage].currentPower * 40.0f) / stage[currentStage].powerToComplete;
	powerMeterSprite->setSpriteClip(40, 0, (int)percent, 7);
	powerMeterSprite->render();

	// HI-SCORE
	textScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset3, lang->getText(56));
	if (options->online.enabled)
	{
		if (jscore::getNumUsers() > 0)
		{
			const std::string txt = jscore::getUserName(0).substr(0, 12) + " - " + updateScoreText((Uint32)jscore::getPoints(0));
			textScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset4, txt);
		}
		else
		{
			textScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset4, "Bacteriol - 0000010");
		}
	}
	else
	{
		textScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset4, updateScoreText(hiScore));
	}
}

// Actualiza las variables del jugador
void Game::updatePlayers()
{
	for (auto player : players)
	{
		player->update();

		// Comprueba la colisión entre el jugador y los globos
		if (checkPlayerBalloonCollision(player))
		{
			if (player->isAlive())
			{
				if (demo.enabled)
				{
					section->name = SECTION_PROG_TITLE;
					section->subsection = SUBSECTION_TITLE_INSTRUCTIONS;
				}
				else
				{
					killPlayer(player);
				}
			}
		}

		// Comprueba las colisiones entre el jugador y los items
		checkPlayerItemCollision(player);
	}
}

// Dibuja a los jugadores
void Game::renderPlayers()
{
	for (auto player : players)
	{
		player->render();
	}
}

// Actualiza las variables de la fase
void Game::updateStage()
{
	if (stage[currentStage].currentPower >= stage[currentStage].powerToComplete)
	{
		// Cambio de fase
		currentStage++;
		lastStageReached = currentStage;
		if (currentStage == 10)
		{										  // Ha llegado al final el juego
			gameCompleted = true;				  // Marca el juego como completado
			currentStage = 9;					  // Deja el valor dentro de los limites
			stage[currentStage].currentPower = 0; // Deja el poder a cero para que no vuelva a entrar en esta condición
			destroyAllBalloons();				  // Destruye a todos los enemigos
			stage[currentStage].currentPower = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos lo globos
			menaceCurrent = 255;				  // Sube el nivel de amenaza para que no cree mas globos
			for (auto player : players)
			{ // Añade un millon de puntos a los jugadores que queden vivos
				if (player->isAlive())
				{
					player->addScore(1000000);
				}
			}
			updateHiScore();
			JA_StopMusic();
		}
		JA_PlaySound(stageChangeSound);
		stageBitmapCounter = 0;
		enemySpeed = defaultEnemySpeed;
		setBalloonSpeed(enemySpeed);
		effect.flash = true;
		effect.shake = true;
	}

	// Incrementa el contador del bitmap que aparece mostrando el cambio de fase
	if (stageBitmapCounter < STAGE_COUNTER)
	{
		stageBitmapCounter++;
	}

	// Si el juego se ha completado, el bitmap se detiene en el centro de la pantalla
	if (gameCompleted)
	{
		if (stageBitmapCounter > 100)
		{
			stageBitmapCounter = 100;
		}
	}
}

// Actualiza el estado de muerte
void Game::updateDeath()
{
	// Comprueba si todos los jugadores estan muertos
	bool allPlayersAreDead = true;
	for (auto player : players)
	{
		allPlayersAreDead &= (!player->isAlive());
	}

	if (allPlayersAreDead)
	{
		if (deathCounter > 0)
		{
			deathCounter--;

			if ((deathCounter == 250) || (deathCounter == 200) || (deathCounter == 180) || (deathCounter == 120) || (deathCounter == 60))
			{
				// Hace sonar aleatoriamente uno de los 4 sonidos de burbujas
				const Uint8 index = rand() % 4;
				JA_Sound_t *sound[4] = {bubble1Sound, bubble2Sound, bubble3Sound, bubble4Sound};
				JA_PlaySound(sound[index], 0);
			}
		}
		else
		{
			section->subsection = SUBSECTION_GAME_GAMEOVER;
		}
	}
}

// Renderiza el fade final cuando se acaba la partida
void Game::renderDeathFade(int counter)
{ // Counter debe ir de 0 a 150
	SDL_SetRenderDrawColor(renderer, 0x27, 0x27, 0x36, 255);

	if (counter < 150)
	{
		// 192 / 6 = 32, 6 cuadrados de 32 pixeles
		SDL_Rect rect[12];
		Uint8 h = counter / 3;
		for (int i = 0; i < 12; ++i)
		{
			rect[i].x = 0;
			rect[i].y = i * 16;
			rect[i].w = GAMECANVAS_WIDTH;
			if (i == 0)
			{
				rect[i].h = h;
			}
			else
			{
				rect[i].h = std::max(rect[i - 1].h - 3, 0);
			}
			SDL_RenderFillRect(renderer, &rect[i]);
		}
	}
	else
	{
		SDL_Rect rect = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
		SDL_RenderFillRect(renderer, &rect);
	}
}

// Actualiza los globos
void Game::updateBalloons()
{
	for (auto balloon : balloons)
	{
		balloon->update();
	}
}

// Pinta en pantalla todos los globos activos
void Game::renderBalloons()
{
	for (auto balloon : balloons)
	{
		balloon->render();
	}
}

// Crea un globo nuevo en el vector de globos
Uint8 Game::createBalloon(float x, int y, Uint8 kind, float velx, float speed, Uint16 creationtimer)
{
	const int index = (kind - 1) % 4;
	Balloon *b = new Balloon(x, y, kind, velx, speed, creationtimer, balloonTextures[index], balloonAnimations[index], renderer);
	balloons.push_back(b);
	return (Uint8)(balloons.size() - 1);
}

// Crea una PowerBall
void Game::createPowerBall()
{
	const int posY = PLAY_AREA_TOP;

	const int left = PLAY_AREA_LEFT;
	const int center = PLAY_AREA_CENTER_X - (BALLOON_WIDTH_4 / 2);
	const int right = PLAY_AREA_RIGHT - BALLOON_WIDTH_4;

	const int luck = rand() % 3;
	const int x[3] = {left, center, right};
	const float vx[3] = {BALLOON_VELX_POSITIVE, BALLOON_VELX_POSITIVE, BALLOON_VELX_NEGATIVE};

	Balloon *b = new Balloon(x[luck], posY, POWER_BALL, vx[luck], enemySpeed, 100, balloonTextures[3], balloonAnimations[3], renderer);
	balloons.push_back(b);

	powerBallEnabled = true;
	powerBallCounter = POWERBALL_COUNTER;
}

// Establece la velocidad de los globos
void Game::setBalloonSpeed(float speed)
{
	for (auto balloon : balloons)
	{
		if (balloon->isEnabled())
		{
			balloon->setSpeed(speed);
		}
	}
}

// Incrementa la velocidad de los globos
void Game::incBalloonSpeed()
{
	// La velocidad solo se incrementa en el modo normal
	if (difficulty == DIFFICULTY_NORMAL)
	{
		if (enemySpeed == BALLOON_SPEED_1)
		{
			enemySpeed = BALLOON_SPEED_2;
		}

		else if (enemySpeed == BALLOON_SPEED_2)
		{
			enemySpeed = BALLOON_SPEED_3;
		}

		else if (enemySpeed == BALLOON_SPEED_3)
		{
			enemySpeed = BALLOON_SPEED_4;
		}

		else if (enemySpeed == BALLOON_SPEED_4)
		{
			enemySpeed = BALLOON_SPEED_5;
		}

		setBalloonSpeed(enemySpeed);
	}
}

// Decrementa la velocidad de los globos
void Game::decBalloonSpeed()
{
	// La velocidad solo se decrementa en el modo normal
	if (difficulty == DIFFICULTY_NORMAL)
	{
		if (enemySpeed == BALLOON_SPEED_5)
		{
			enemySpeed = BALLOON_SPEED_4;
		}

		else if (enemySpeed == BALLOON_SPEED_4)
		{
			enemySpeed = BALLOON_SPEED_3;
		}

		else if (enemySpeed == BALLOON_SPEED_3)
		{
			enemySpeed = BALLOON_SPEED_2;
		}

		else if (enemySpeed == BALLOON_SPEED_2)
		{
			enemySpeed = BALLOON_SPEED_1;
		}

		setBalloonSpeed(enemySpeed);
	}
}

// Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
void Game::updateBalloonSpeed()
{
	const float percent = (float)stage[currentStage].currentPower / (float)stage[currentStage].powerToComplete;
	if (enemySpeed == BALLOON_SPEED_1)
	{
		if (percent > 0.2f)
		{
			incBalloonSpeed();
		}
	}

	else if (enemySpeed == BALLOON_SPEED_2)
	{
		if (percent > 0.4f)
		{
			incBalloonSpeed();
		}
	}

	else if (enemySpeed == BALLOON_SPEED_3)
	{
		if (percent > 0.6f)
		{
			incBalloonSpeed();
		}
	}

	else if (enemySpeed == BALLOON_SPEED_4)
	{
		if (percent > 0.8f)
		{
			incBalloonSpeed();
		}
	}
}

// Explosiona un globo. Lo destruye y crea otros dos si es el caso
void Game::popBalloon(Balloon *balloon)
{
	// Aumenta el poder de la fase
	increaseStageCurrentPower(1);
	balloonsPopped++;

	const Uint8 kind = balloon->getKind();
	switch (kind)
	{
	// Si es del tipo más pequeño, simplemente elimina el globo
	case BALLOON_1:
		balloon->pop();
		break;

	case HEXAGON_1:
		balloon->pop();
		break;

	// Si es del tipo PowerBall, destruye todos los globos
	case POWER_BALL:
		destroyAllBalloons();
		powerBallEnabled = false;
		enemyDeployCounter = 20;
		break;

	// En cualquier otro caso, crea dos globos de un tipo inferior
	default:
		const int index = createBalloon(0, balloon->getPosY(), balloon->getKind() - 1, BALLOON_VELX_NEGATIVE, enemySpeed, 0);
		balloons[index]->allignTo(balloon->getPosX() + (balloon->getWidth() / 2));
		if (balloons[index]->getClass() == BALLOON_CLASS)
		{
			balloons[index]->setVelY(-2.50f);
		}
		else
		{
			balloons[index]->setVelY(BALLOON_VELX_NEGATIVE);
		}

		const int index2 = createBalloon(0, balloon->getPosY(), balloon->getKind() - 1, BALLOON_VELX_POSITIVE, enemySpeed, 0);
		balloons[index2]->allignTo(balloon->getPosX() + (balloon->getWidth() / 2));
		if (balloons[index2]->getClass() == BALLOON_CLASS)
		{
			balloons[index2]->setVelY(-2.50f);
		}
		else
		{
			balloons[index2]->setVelY(BALLOON_VELX_NEGATIVE);
		}

		// Elimina el globo
		balloon->pop();
		break;
	}

	// Recalcula el nivel de amenaza
	evaluateAndSetMenace();
}

// Explosiona un globo. Lo destruye
void Game::destroyBalloon(Balloon *balloon)
{
	int score = 0;
	Uint8 power = 0;

	// Calcula la puntuación y el poder que generaria el globo en caso de romperlo a él y a sus hijos
	switch (balloon->getSize())
	{
	case BALLOON_SIZE_4:
		score = BALLOON_SCORE_4 + (2 * BALLOON_SCORE_3) + (4 * BALLOON_SCORE_2) + (8 * BALLOON_SCORE_1);
		power = 15;
		break;

	case BALLOON_SIZE_3:
		score = BALLOON_SCORE_3 + (2 * BALLOON_SCORE_2) + (4 * BALLOON_SCORE_1);
		power = 7;
		break;

	case BALLOON_SIZE_2:
		score = BALLOON_SCORE_2 + (2 * BALLOON_SCORE_1);
		power = 3;
		break;

	case BALLOON_SIZE_1:
		score = BALLOON_SCORE_1;
		power = 1;
		break;

	default:
		score = 0;
		power = 0;
		break;
	}

	// Otorga los puntos correspondientes al globo
	for (auto player : players)
	{
		player->addScore(Uint32(score * player->getScoreMultiplier() * difficultyScoreMultiplier));
	}
	updateHiScore();

	// Aumenta el poder de la fase
	increaseStageCurrentPower(power);
	balloonsPopped += power;

	// Destruye el globo
	balloon->pop();

	// Recalcula el nivel de amenaza
	evaluateAndSetMenace();
}

// Explosiona todos los globos
void Game::popAllBalloons()
{
	for (auto balloon : balloons)
	{
		if ((balloon->isEnabled()) && (!balloon->isPopping()) && (!balloon->isBeingCreated()))
		{
			popBalloon(balloon);
		}
	}

	JA_PlaySound(balloonSound);
}

// Destruye todos los globos
void Game::destroyAllBalloons()
{
	for (auto balloon : balloons)
	{
		if ((balloon->isEnabled()) && (!balloon->isPopping()))
		{
			destroyBalloon(balloon);
		}
	}

	enemyDeployCounter = 255;
	JA_PlaySound(powerBallSound);
	effect.flash = true;
	effect.shake = true;
}

// Detiene todos los globos
void Game::stopAllBalloons(Uint16 time)
{
	for (auto balloon : balloons)
	{
		if (balloon->isEnabled())
		{
			balloon->setStop(true);
			balloon->setStoppedTimer(time);
		}
	}
}

// Pone en marcha todos los globos
void Game::startAllBalloons()
{
	for (auto balloon : balloons)
	{
		if ((balloon->isEnabled()) && (!balloon->isBeingCreated()))
		{
			balloon->setStop(false);
			balloon->setStoppedTimer(0);
		}
	}
}

// Obtiene el numero de globos activos
Uint8 Game::countBalloons()
{
	Uint8 num = 0;

	for (auto balloon : balloons)
	{
		if (balloon->isEnabled())
		{
			if (!balloon->isPopping())
			{
				num++;
			}
		}
	}

	return num;
}

// Vacia el vector de globos
void Game::freeBalloons()
{
	if (balloons.empty() == false)
	{
		for (int i = balloons.size() - 1; i >= 0; --i)
		{
			if (balloons[i]->isEnabled() == false)
			{
				delete balloons[i];
				balloons.erase(balloons.begin() + i);
			}
		}
	}
}

// Comprueba la colisión entre el jugador y los globos activos
bool Game::checkPlayerBalloonCollision(Player *player)
{
	for (auto balloon : balloons)
	{
		if ((balloon->isEnabled()) && !(balloon->isStopped()) && !(balloon->isInvulnerable()))
		{
			if (checkCollision(player->getCollider(), balloon->getCollider()))
			{
				return true;
			}
		}
	}

	return false;
}

// Comprueba la colisión entre el jugador y los items
void Game::checkPlayerItemCollision(Player *player)
{
	if (!player->isAlive())
	{
		return;
	}

	for (auto item : items)
	{
		if (item->isEnabled())
		{
			if (checkCollision(player->getCollider(), item->getCollider()))
			{
				switch (item->getClass())
				{
				case ITEM_POINTS_1_DISK:
					player->addScore(1000);
					updateHiScore();
					createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n1000Sprite->getWidth() / 2), player->getPosY(), n1000Sprite);
					JA_PlaySound(itemPickUpSound);
					break;

				case ITEM_POINTS_2_GAVINA:
					player->addScore(2500);
					updateHiScore();
					createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n2500Sprite->getWidth() / 2), player->getPosY(), n2500Sprite);
					JA_PlaySound(itemPickUpSound);
					break;

				case ITEM_POINTS_3_PACMAR:
					player->addScore(5000);
					updateHiScore();
					createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n5000Sprite->getWidth() / 2), player->getPosY(), n5000Sprite);
					JA_PlaySound(itemPickUpSound);
					break;

				case ITEM_CLOCK:
					enableTimeStopItem();
					JA_PlaySound(itemPickUpSound);
					break;

				case ITEM_COFFEE:
					if (player->getCoffees() == 2)
					{
						player->addScore(5000);
						updateHiScore();
						createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n5000Sprite->getWidth() / 2), player->getPosY(), n5000Sprite);
					}
					player->giveExtraHit();
					JA_PlaySound(itemPickUpSound);
					break;

				case ITEM_COFFEE_MACHINE:
					player->setPowerUp(true);
					JA_PlaySound(itemPickUpSound);
					coffeeMachineEnabled = false;
					break;

				default:
					break;
				}

				item->disable();
			}
		}
	}
}

// Comprueba y procesa la colisión entre las balas y los globos
void Game::checkBulletBalloonCollision()
{
	for (auto bullet : bullets)
	{
		for (auto balloon : balloons)
		{
			if (balloon->isEnabled() && (!balloon->isInvulnerable()) && bullet->isEnabled())
			{
				if (checkCollision(balloon->getCollider(), bullet->getCollider()))
				{
					// Otorga los puntos correspondientes al globo al jugador que disparó la bala
					int index = bullet->getOwner();
					players[index]->incScoreMultiplier();
					players[index]->addScore(Uint32(balloon->getScore() * players[index]->getScoreMultiplier() * difficultyScoreMultiplier));
					updateHiScore();

					// Explota el globo
					popBalloon(balloon);

					// Si no es el modo demo, genera un sonido
					if (!demo.enabled)
					{
						JA_PlaySound(balloonSound);
					}

					// Deshabilita la bala
					bullet->disable();

					// Suelta el item en caso de que salga uno
					const Uint8 droppeditem = dropItem();
					if ((droppeditem != NO_KIND) && !(demo.enabled) && !(demo.recording))
					{
						if (droppeditem != ITEM_COFFEE_MACHINE)
						{
							createItem(droppeditem, balloon->getPosX(), balloon->getPosY());
							JA_PlaySound(itemDropSound);
						}
						else
						{
							createItem(droppeditem, players[index]->getPosX(), 0);
							coffeeMachineEnabled = true;
						}
					}

					break;
				}
			}
		}
	}
}

// Mueve las balas activas
void Game::moveBullets()
{
	for (auto bullet : bullets)
	{
		if (bullet->isEnabled())
		{
			if (bullet->move() == BULLET_MOVE_OUT)
			{
				players[bullet->getOwner()]->decScoreMultiplier();
			}
		}
	}
}

// Pinta las balas activas
void Game::renderBullets()
{
	for (auto bullet : bullets)
	{
		if (bullet->isEnabled())
		{
			bullet->render();
		}
	}
}

// Crea un objeto bala
void Game::createBullet(int x, int y, Uint8 kind, bool poweredUp, int owner)
{
	Bullet *b = new Bullet(x, y, kind, poweredUp, owner, bulletTexture, renderer);
	bullets.push_back(b);
}

// Vacia el vector de balas
void Game::freeBullets()
{
	if (bullets.empty() == false)
	{
		for (int i = bullets.size() - 1; i >= 0; --i)
		{
			if (bullets[i]->isEnabled() == false)
			{
				delete bullets[i];
				bullets.erase(bullets.begin() + i);
			}
		}
	}
}

// Actualiza los items
void Game::updateItems()
{
	for (auto item : items)
	{
		if (item->isEnabled())
		{
			item->update();
			if (item->isOnFloor())
			{
				JA_PlaySound(coffeeMachineSound);
				effect.shake = true;
			}
		}
	}
}

// Pinta los items activos
void Game::renderItems()
{
	for (auto item : items)
	{
		item->render();
	}
}

// Devuelve un item en función del azar
Uint8 Game::dropItem()
{
	const Uint8 luckyNumber = rand() % 100;
	const Uint8 item = rand() % 6;

	switch (item)
	{
	case 0:
		if (luckyNumber < helper.itemPoints1Odds)
		{
			return ITEM_POINTS_1_DISK;
		}
		break;

	case 1:
		if (luckyNumber < helper.itemPoints2Odds)
		{
			return ITEM_POINTS_2_GAVINA;
		}
		break;

	case 2:
		if (luckyNumber < helper.itemPoints3Odds)
		{
			return ITEM_POINTS_3_PACMAR;
		}
		break;

	case 3:
		if (luckyNumber < helper.itemClockOdds)
		{
			return ITEM_CLOCK;
		}
		break;

	case 4:
		if (luckyNumber < helper.itemCoffeeOdds)
		{
			helper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
			return ITEM_COFFEE;
		}
		else
		{
			if (helper.needCoffee)
			{
				helper.itemCoffeeOdds++;
			}
		}
		break;

	case 5:
		if (luckyNumber < helper.itemCoffeeMachineOdds)
		{
			helper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
			if ((!coffeeMachineEnabled) && (helper.needCoffeeMachine))
			{
				return ITEM_COFFEE_MACHINE;
			}
		}
		else
		{
			if (helper.needCoffeeMachine)
			{
				helper.itemCoffeeMachineOdds++;
			}
		}
		break;

	default:
		break;
	}

	return NO_KIND;
}

// Crea un objeto item
void Game::createItem(Uint8 kind, float x, float y)
{
	Item *item = new Item(kind, x, y, itemTextures[kind], itemAnimations[kind], renderer);
	items.push_back(item);
}

// Vacia el vector de items
void Game::freeItems()
{
	if (items.empty() == false)
	{
		for (int i = items.size() - 1; i >= 0; --i)
		{
			if (items[i]->isEnabled() == false)
			{
				delete items[i];
				items.erase(items.begin() + i);
			}
		}
	}
}

// Crea un objeto SmartSprite para mostrar la puntuación al coger un objeto
void Game::createItemScoreSprite(int x, int y, SmartSprite *sprite)
{
	SmartSprite *ss = new SmartSprite(nullptr, renderer);
	smartSprites.push_back(ss);

	// Crea una copia del objeto
	*ss = *sprite;
	ss->setPosX(x);
	ss->setPosY(y);
	ss->setDestX(x);
	ss->setDestY(y - 15);
	ss->setEnabled(true);
	ss->setEnabledCounter(100);
}

// Vacia el vector de smartsprites
void Game::freeSmartSprites()
{
	if (smartSprites.empty() == false)
	{
		for (int i = smartSprites.size() - 1; i >= 0; --i)
		{
			if (smartSprites[i]->hasFinished())
			{
				delete smartSprites[i];
				smartSprites.erase(smartSprites.begin() + i);
			}
		}
	}
}

// Dibuja el efecto de flash
void Game::renderFlashEffect()
{
	if (effect.flash)
	{
		// Pantallazo blanco
		SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
		SDL_RenderClear(renderer);

		effect.flash = false;
	}
}

// Actualiza el efecto de agitar la pantalla
void Game::updateShakeEffect()
{
	if (effect.shake)
	{
		if (effect.shakeCounter > 0)
		{
			effect.shakeCounter--;
		}
		else
		{
			effect.shake = false;
			effect.shakeCounter = SHAKE_COUNTER;
		}
	}
}

// Crea un SmartSprite para arrojar el item café al recibir un impacto
void Game::throwCoffee(int x, int y)
{
	SmartSprite *ss = new SmartSprite(itemTextures[4], renderer);
	smartSprites.push_back(ss);

	ss->setPosX(x - 8);
	ss->setPosY(y - 8);
	ss->setWidth(16);
	ss->setHeight(16);
	ss->setVelX(-1.0f + ((rand() % 5) * 0.5f));
	ss->setVelY(-4.0f);
	ss->setAccelX(0.0f);
	ss->setAccelY(0.2f);
	ss->setDestX(x + (ss->getVelX() * 50));
	ss->setDestY(GAMECANVAS_HEIGHT + 1);
	ss->setEnabled(true);
	ss->setEnabledCounter(1);
	ss->setSpriteClip(0, 0, 16, 16);
	ss->setRotate(true);
	ss->setRotateSpeed(10);
	ss->setRotateAmount(90.0);
}

// Actualiza los SmartSprites
void Game::updateSmartSprites()
{
	for (auto ss : smartSprites)
	{
		ss->update();
	}
}

// Pinta los SmartSprites activos
void Game::renderSmartSprites()
{
	for (auto ss : smartSprites)
	{
		ss->render();
	}
}

// Acciones a realizar cuando el jugador muere
void Game::killPlayer(Player *player)
{
	if (!player->isInvulnerable())
	{
		if (player->hasExtraHit())
		{
			player->removeExtraHit();
			throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
			JA_PlaySound(coffeeOutSound);
		}
		else
		{
			JA_PauseMusic();
			stopAllBalloons(10);
			JA_PlaySound(playerCollisionSound);
			shakeScreen();
			SDL_Delay(500);
			JA_PlaySound(coffeeOutSound);
			player->setAlive(false);
			if (allPlayersAreDead())
			{
				JA_StopMusic();
			}
			else
			{
				JA_ResumeMusic();
			}
		}
	}
}

// Calcula y establece el valor de amenaza en funcion de los globos activos
void Game::evaluateAndSetMenace()
{
	menaceCurrent = 0;
	for (auto balloon : balloons)
	{
		if (balloon->isEnabled())
		{
			menaceCurrent += balloon->getMenace();
		}
	}
}

// Obtiene el valor de la variable
Uint8 Game::getMenace()
{
	return menaceCurrent;
}

// Establece el valor de la variable
void Game::setTimeStopped(bool value)
{
	timeStopped = value;
}

// Obtiene el valor de la variable
bool Game::isTimeStopped()
{
	return timeStopped;
}

// Establece el valor de la variable
void Game::setTimeStoppedCounter(Uint16 value)
{
	timeStoppedCounter = value;
}

// Incrementa el valor de la variable
void Game::incTimeStoppedCounter(Uint16 value)
{
	timeStoppedCounter += value;
}

// Actualiza y comprueba el valor de la variable
void Game::updateTimeStoppedCounter()
{
	if (isTimeStopped())
	{
		if (timeStoppedCounter > 0)
		{
			timeStoppedCounter--;
			stopAllBalloons(TIME_STOPPED_COUNTER);
		}
		else
		{
			disableTimeStopItem();
		}
	}
}

// Actualiza la variable enemyDeployCounter
void Game::updateEnemyDeployCounter()
{
	if (enemyDeployCounter > 0)
	{
		enemyDeployCounter--;
	}
}

// Actualiza el juego
void Game::update()
{
	// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
	if (SDL_GetTicks() - ticks > ticksSpeed)
	{
		// Actualiza el contador de ticks
		ticks = SDL_GetTicks();

		// Actualiza las notificaciones
		screen->updateNotifier();

		// Actualiza el contador de juego
		counter++;

		// Comprueba el teclado/mando
		checkGameInput();

		// Actualiza las variables del jugador
		updatePlayers();

		// Actualiza el fondo
		updateBackground();

		// Mueve los globos
		updateBalloons();

		// Mueve las balas
		moveBullets();

		// Actualiza los items
		updateItems();

		// Actualiza el valor de currentStage
		updateStage();

		// Actualiza el estado de muerte
		updateDeath();

		// Actualiza los SmartSprites
		updateSmartSprites();

		// Actualiza los contadores de estado y efectos
		updateTimeStoppedCounter();
		updateEnemyDeployCounter();
		updateShakeEffect();

		// Actualiza el ayudante
		updateHelper();

		// Comprueba las colisiones entre globos y balas
		checkBulletBalloonCollision();

		// Comprueba el nivel de amenaza para ver si se han de crear nuevos enemigos
		updateMenace();

		// Actualiza la velocidad de los enemigos
		updateBalloonSpeed();

		// Actualiza el tramo final de juego, una vez completado
		updateGameCompleted();

		// Vacia los vectores
		freeBullets();
		freeBalloons();
		freeItems();
		freeSmartSprites();
	}
}

// Actualiza el fondo
void Game::updateBackground()
{
	if (!gameCompleted)
	{ // Si el juego no esta completo, la velocidad de las nubes es igual a los globos explotados
		cloudsSpeed = balloonsPopped;
	}
	else
	{ // Si el juego está completado, se reduce la velocidad de las nubes
		if (cloudsSpeed > 400)
		{
			cloudsSpeed -= 25;
		}
		else
		{
			cloudsSpeed = 200;
		}
	}

	// Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego
	const float speed = (-0.2f) + (-3.00f * ((float)cloudsSpeed / (float)totalPowerToCompleteGame));

	// Aplica la velocidad calculada a las nubes
	clouds1A->setVelX(speed);
	clouds1B->setVelX(speed);
	clouds2A->setVelX(speed / 2);
	clouds2B->setVelX(speed / 2);

	// Mueve las nubes
	clouds1A->move();
	clouds1B->move();
	clouds2A->move();
	clouds2B->move();

	// Calcula el offset de las nubes
	if (clouds1A->getPosX() < -clouds1A->getWidth())
	{
		clouds1A->setPosX(clouds1A->getWidth());
	}

	if (clouds1B->getPosX() < -clouds1B->getWidth())
	{
		clouds1B->setPosX(clouds1B->getWidth());
	}

	if (clouds2A->getPosX() < -clouds2A->getWidth())
	{
		clouds2A->setPosX(clouds2A->getWidth());
	}

	if (clouds2B->getPosX() < -clouds2B->getWidth())
	{
		clouds2B->setPosX(clouds2B->getWidth());
	}

	// Calcula el frame de la hierba
	grassSprite->setSpriteClip(0, (6 * (counter / 20 % 2)), 256, 6);

	// Mueve los edificios en funcion de si está activo el efecto de agitarlos
	if (effect.shake)
	{
		buildingsSprite->setPosX(((effect.shakeCounter % 2) * 2) - 1);
	}
	else
	{
		buildingsSprite->setPosX(0);
	}
}

// Dibuja el fondo
void Game::renderBackground()
{
	const float gradientNumber = std::min(((float)balloonsPopped / 1250.0f), 3.0f);
	const float percent = gradientNumber - (int)gradientNumber;
	const int alpha = std::max((255 - (int)(255 * percent)), 0);

	// Dibuja el gradiente 2
	skyColorsSprite->setSpriteClip(skyColorsRect[((int)gradientNumber + 1) % 4]);
	gameSkyColorsTexture->setAlpha(255);
	skyColorsSprite->render();

	// Dibuja el gradiente 1 con una opacidad cada vez menor
	skyColorsSprite->setSpriteClip(skyColorsRect[(int)gradientNumber]);
	gameSkyColorsTexture->setAlpha(alpha);
	skyColorsSprite->render();

	// Dibuja las nubes
	clouds1A->render();
	clouds1B->render();
	clouds2A->render();
	clouds2B->render();

	// Dinuja los edificios
	buildingsSprite->render();

	// Dibuja la hierba
	grassSprite->render();
}

// Dibuja el juego
void Game::render()
{
	// Prepara para empezar a dibujar en la textura de juego
	screen->start();

	// Limpia la pantalla
	screen->clean(bgColor);

	// Dibuja los objetos
	renderBackground();
	renderBalloons();
	renderBullets();
	renderMessages();
	renderItems();
	renderSmartSprites();
	renderScoreBoard();
	renderPlayers();

	if ((deathCounter <= 150) && !players[0]->isAlive())
	{
		renderDeathFade(150 - deathCounter);
	}

	if ((gameCompleted) && (gameCompletedCounter >= GAME_COMPLETED_START_FADE))
	{
		renderDeathFade(gameCompletedCounter - GAME_COMPLETED_START_FADE);
	}

	renderFlashEffect();

	// Vuelca el contenido del renderizador en pantalla
	screen->blit();
}

// Gestiona el nivel de amenaza
void Game::updateMenace()
{
	if (gameCompleted)
	{
		return;
	}

	const float percent = stage[currentStage].currentPower / stage[currentStage].powerToComplete;
	const Uint8 difference = stage[currentStage].maxMenace - stage[currentStage].minMenace;

	// Aumenta el nivel de amenaza en función de la puntuación
	menaceThreshold = stage[currentStage].minMenace + (difference * percent);

	// Si el nivel de amenza es inferior al umbral
	if (menaceCurrent < menaceThreshold)
	{
		// Crea una formación de enemigos
		deployEnemyFormation();

		// Recalcula el nivel de amenaza con el nuevo globo
		evaluateAndSetMenace();
	}
}

// Gestiona la entrada durante el juego
void Game::checkGameInput()
{
	demo.keys.left = 0;
	demo.keys.right = 0;
	demo.keys.noInput = 0;
	demo.keys.fire = 0;
	demo.keys.fireLeft = 0;
	demo.keys.fireRight = 0;

	// Comprueba las teclas de cambiar el tamaño de la centana y el modo de video
	if (input->checkInput(input_window_fullscreen, REPEAT_FALSE))
	{
		screen->switchVideoMode();
	}

	else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
	{
		screen->decWindowSize();
	}

	else if (input->checkInput(input_window_inc_size, REPEAT_FALSE))
	{
		screen->incWindowSize();
	}

	// Modo Demo activo
	if (demo.enabled)
	{
		const int index = 0;
		if (demo.dataFile[demo.counter].left == 1)
		{
			players[index]->setInput(input_left);
		}

		if (demo.dataFile[demo.counter].right == 1)
		{
			players[index]->setInput(input_right);
		}

		if (demo.dataFile[demo.counter].noInput == 1)
		{
			players[index]->setInput(input_null);
		}

		if (demo.dataFile[demo.counter].fire == 1)
		{
			if (players[index]->canFire())
			{
				players[index]->setInput(input_fire_center);
				createBullet(players[index]->getPosX() + (players[index]->getWidth() / 2) - 4, players[index]->getPosY() + (players[index]->getHeight() / 2), BULLET_UP, players[index]->isPowerUp(), index);
				players[index]->setFireCooldown(10);
			}
		}

		if (demo.dataFile[demo.counter].fireLeft == 1)
		{
			if (players[index]->canFire())
			{
				players[index]->setInput(input_fire_left);
				createBullet(players[index]->getPosX() + (players[index]->getWidth() / 2) - 4, players[index]->getPosY() + (players[index]->getHeight() / 2), BULLET_UP, players[index]->isPowerUp(), index);
				players[index]->setFireCooldown(10);
			}
		}

		if (demo.dataFile[demo.counter].fireRight == 1)
		{
			if (players[index]->canFire())
			{
				players[index]->setInput(input_fire_right);
				createBullet(players[index]->getPosX() + (players[index]->getWidth() / 2) - 4, players[index]->getPosY() + (players[index]->getHeight() / 2), BULLET_UP, players[index]->isPowerUp(), index);
				players[index]->setFireCooldown(10);
			}
		}

		// Comprueba el input de pausa
		if (input->checkInput(input_pause, REPEAT_FALSE))
		{
			section->name = SECTION_PROG_TITLE;
		}

		// Incrementa el contador de la demo
		if (demo.counter < TOTAL_DEMO_DATA)
		{
			demo.counter++;
		}
		else
		{
			section->name = SECTION_PROG_TITLE;
			section->subsection = SUBSECTION_TITLE_INSTRUCTIONS;
		}
	}
	// Modo Demo no activo
	else
	{
		int i = 0;
		for (auto player : players)
		{
			if (player->isAlive())
			{
				// Input a la izquierda
				if (input->checkInput(input_left, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id))
				{
					player->setInput(input_left);
					demo.keys.left = 1;
				}
				else
				{
					// Input a la derecha
					if (input->checkInput(input_right, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id))
					{
						player->setInput(input_right);
						demo.keys.right = 1;
					}
					else
					{
						// Ninguno de los dos inputs anteriores
						player->setInput(input_null);
						demo.keys.noInput = 1;
					}
				}
				// Comprueba el input de disparar al centro
				if (input->checkInput(input_fire_center, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id))
				{
					if (player->canFire())
					{
						player->setInput(input_fire_center);
						createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_UP, player->isPowerUp(), i);
						player->setFireCooldown(10);

						// Reproduce el sonido de disparo
						JA_PlaySound(bulletSound);

						demo.keys.fire = 1;
					}
				}

				// Comprueba el input de disparar a la izquierda
				if (input->checkInput(input_fire_left, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id))
				{
					if (player->canFire())
					{
						player->setInput(input_fire_left);
						createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_LEFT, player->isPowerUp(), i);
						player->setFireCooldown(10);

						// Reproduce el sonido de disparo
						JA_PlaySound(bulletSound);

						demo.keys.fireLeft = 1;
					}
				}

				// Comprueba el input de disparar a la derecha
				if (input->checkInput(input_fire_right, REPEAT_TRUE, options->input[i].deviceType, options->input[i].id))
				{
					if (player->canFire())
					{
						player->setInput(input_fire_right);
						createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_RIGHT, player->isPowerUp(), i);
						player->setFireCooldown(10);

						// Reproduce el sonido de disparo
						JA_PlaySound(bulletSound);

						demo.keys.fireRight = 1;
					}
				}

				// Comprueba el input de pausa
				if (input->checkInput(input_cancel, REPEAT_FALSE, options->input[i].deviceType, options->input[i].id))
				{
					section->subsection = SUBSECTION_GAME_PAUSE;
				}

				if (demo.counter < TOTAL_DEMO_DATA)
				{
					if (demo.recording)
					{
						demo.dataFile[demo.counter] = demo.keys;
					}
					demo.counter++;
				}
				else if (demo.recording)
				{
					section->name = SECTION_PROG_QUIT;
				}

				i++;
			}
		}
	}
}

// Pinta diferentes mensajes en la pantalla
void Game::renderMessages()
{
	// GetReady
	if ((counter < STAGE_COUNTER) && (!demo.enabled))
	{
		textNokiaBig2->write((int)getReadyBitmapPath[counter], PLAY_AREA_CENTER_Y - 8, lang->getText(75), -2);
	}

	// Time Stopped
	if (timeStopped)
	{
		if ((timeStoppedCounter > 100) || (timeStoppedCounter % 10 > 4))
		{
			textNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, lang->getText(36) + std::to_string(timeStoppedCounter / 10), -1, noColor, 1, shdwTxtColor);
		}

		if (timeStoppedCounter > 100)
		{
			if (timeStoppedCounter % 30 == 0)
			{
				JA_PlaySound(clockSound, false);
			}
		}
		else
		{
			if (timeStoppedCounter % 15 == 0)
			{
				JA_PlaySound(clockSound, false);
			}
		}
	}

	// D E M O
	if (demo.enabled)
	{
		if (demo.counter % 30 > 14)
		{
			textNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, lang->getText(37), 0, noColor, 2, shdwTxtColor);
		}
	}

	// STAGE NUMBER
	if (stageBitmapCounter < STAGE_COUNTER)
	{
		const int stageNum = stage[currentStage].number;
		std::string text;

		if (stageNum == 10)
		{ // Ultima fase
			text = lang->getText(79);
		}
		else
		{ // X fases restantes
			text = std::to_string(11 - stage[currentStage].number) + lang->getText(38);
		}

		if (!gameCompleted)
		{ // Escribe el numero de fases restantes
			textNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, stageBitmapPath[stageBitmapCounter], text, -2, noColor, 2, shdwTxtColor);
		}
		else
		{ // Escribe el texto de juego completado
			text = lang->getText(50);
			textNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, stageBitmapPath[stageBitmapCounter], text, -2, noColor, 1, shdwTxtColor);
			textNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, stageBitmapPath[stageBitmapCounter] + textNokiaBig2->getCharacterSize() + 2, lang->getText(76), -1, noColor, 1, shdwTxtColor);
		}
	}
}

// Habilita el efecto del item de detener el tiempo
void Game::enableTimeStopItem()
{
	stopAllBalloons(TIME_STOPPED_COUNTER);
	setTimeStopped(true);
	incTimeStoppedCounter(TIME_STOPPED_COUNTER);
	if (JA_GetMusicState() == JA_MUSIC_PLAYING)
	{
		JA_PauseMusic();
	}
}

// Deshabilita el efecto del item de detener el tiempo
void Game::disableTimeStopItem()
{
	timeStopped = false;
	setTimeStoppedCounter(0);
	startAllBalloons();
	if (JA_GetMusicState() == JA_MUSIC_PAUSED)
	{
		JA_ResumeMusic();
	}
}

// Agita la pantalla
void Game::shakeScreen()
{
	const int v[] = {-1, 1, -1, 1, -1, 1, -1, 0};
	for (int n = 0; n < 8; ++n)
	{
		// Prepara para empezar a dibujar en la textura de juego
		screen->start();

		// Limpia la pantalla
		screen->clean(bgColor);

		// Dibuja los objetos
		buildingsSprite->setPosX(0);
		buildingsSprite->setWidth(1);
		buildingsSprite->setSpriteClip(0, 0, 1, 160);
		renderBackground();

		buildingsSprite->setPosX(255);
		buildingsSprite->setSpriteClip(255, 0, 1, 160);
		buildingsSprite->render();

		buildingsSprite->setPosX(v[n]);
		buildingsSprite->setWidth(256);
		buildingsSprite->setSpriteClip(0, 0, 256, 160);
		buildingsSprite->render();

		grassSprite->render();
		renderBalloons();
		renderBullets();
		renderItems();
		renderPlayers();
		renderScoreBoard();

		// Vuelca el contenido del renderizador en pantalla
		screen->blit();
		SDL_Delay(50);
	}
}

// Bucle para el juego
void Game::run()
{
	while (section->name == SECTION_PROG_GAME)
	{
		// Sección juego en pausa
		if (section->subsection == SUBSECTION_GAME_PAUSE)
		{
			runPausedGame();
		}

		// Sección Game Over
		if (section->subsection == SUBSECTION_GAME_GAMEOVER)
		{
			runGameOverScreen();
		}

		// Sección juego jugando
		if ((section->subsection == SUBSECTION_GAME_PLAY_1P) || (section->subsection == SUBSECTION_GAME_PLAY_2P))
		{
			// Si la música no está sonando
			if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
			{
				// Reproduce la música
				if (!gameCompleted)
				{
					if (players[0]->isAlive())
					{
						JA_PlayMusic(gameMusic);
					}
				}
			}

			// Actualiza la lógica del juego
			update();

			// Comprueba los eventos que hay en cola
			checkEvents();

			// Dibuja los objetos
			render();
		}
	}
}

// Actualiza las variables del menu de pausa del juego
void Game::updatePausedGame()
{
	// Calcula la lógica de los objetos
	if (SDL_GetTicks() - ticks > ticksSpeed)
	{
		// Actualiza el contador de ticks
		ticks = SDL_GetTicks();

		// Actualiza las notificaciones
		screen->updateNotifier();

		if (leavingPauseMenu)
		{
			if (pauseCounter > 0)
			{ // El contador está descendiendo
				const bool a = pauseCounter == 90;
				const bool b = pauseCounter == 60;
				const bool c = pauseCounter == 30;
				if (a || b || c)
				{
					JA_PlaySound(clockSound);
				}
				pauseCounter--;
			}
			else
			{ // Ha finalizado el contador
				section->name = SECTION_PROG_GAME;
				section->subsection = numPlayers == 1 ? SUBSECTION_GAME_PLAY_1P : SUBSECTION_GAME_PLAY_2P;

				if (JA_GetMusicState() == JA_MUSIC_PAUSED)
				{
					JA_ResumeMusic();
				}
			}
		}
		else
		{ // Actualiza la lógica del menu de pausa
			pauseMenu->update();

			// Comprueba las entradas para el menu
			pauseMenu->checkInput();

			// Comprueba si se ha seleccionado algún item del menú
			switch (pauseMenu->getItemSelected())
			{
			case 1:
				leavingPauseMenu = true;
				break;

			case 2:
				fade->setFadeType(FADE_CENTER);
				fade->activateFade();
				break;

			default:
				break;
			}

			// Actualiza el fade
			fade->update();
			if (fade->hasEnded())
			{
				section->name = SECTION_PROG_TITLE;
				section->subsection = SUBSECTION_TITLE_1;
				JA_StopMusic();
			}
		}
	}
}

// Dibuja el menu de pausa del juego
void Game::renderPausedGame()
{
	// Prepara para empezar a dibujar en la textura de juego
	screen->start();

	// Limpia la pantalla
	screen->clean(bgColor);

	// Pinta el escenario
	{
		renderBackground();
		renderBalloons();
		renderBullets();
		renderMessages();
		renderItems();
		renderSmartSprites();
		renderScoreBoard();
		renderPlayers();

		if ((deathCounter <= 150) && !players[0]->isAlive())
		{
			renderDeathFade(150 - deathCounter);
		}

		if ((gameCompleted) && (gameCompletedCounter >= GAME_COMPLETED_START_FADE))
		{
			renderDeathFade(gameCompletedCounter - GAME_COMPLETED_START_FADE);
		}

		renderFlashEffect();
	}

	if (leavingPauseMenu)
	{
		textNokiaBig2->writeCentered(GAMECANVAS_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, std::to_string((pauseCounter / 30) + 1));
	}
	else
	{
		pauseMenu->render();
	}
	fade->render();

	// Vuelca el contenido del renderizador en pantalla
	screen->blit();
}

// Bucle para el menu de pausa del juego
void Game::runPausedGame()
{
	// Pone en pausa la música
	if (JA_GetMusicState() == JA_MUSIC_PLAYING)
	{
		JA_PauseMusic();
	}

	// Reinicia el menu
	pauseMenu->reset();
	leavingPauseMenu = false;

	// Inicializa variables
	pauseCounter = 90;

	while ((section->subsection == SUBSECTION_GAME_PAUSE) && (section->name == SECTION_PROG_GAME))
	{
		updatePausedGame();
		checkEvents();
		renderPausedGame();
	}
}

// Actualiza los elementos de la pantalla de game over
void Game::updateGameOverScreen()
{
	// Variables
	static int postFade = 0;

	// Calcula la lógica de los objetos
	if (SDL_GetTicks() - ticks > ticksSpeed)
	{
		// Actualiza el contador de ticks
		ticks = SDL_GetTicks();

		// Actualiza las notificaciones
		screen->updateNotifier();

		// Actualiza la lógica del menu
		gameOverMenu->update();

		// Actualiza el fade
		fade->update();

		// Si ha terminado el fade, actua segun se haya operado
		if (fade->hasEnded())
		{
			switch (postFade)
			{
			case 0: // YES
				section->name = SECTION_PROG_GAME;
				deleteAllVectorObjects();
				init();
				section->subsection = numPlayers == 1 ? SUBSECTION_GAME_PLAY_1P : SUBSECTION_GAME_PLAY_2P;
				break;

			case 1: // NO
				section->name = SECTION_PROG_TITLE;
				section->subsection = SUBSECTION_TITLE_1;
				break;

			default:
				break;
			}
		}

		// Comprueba las entradas para el menu solo si no esta el juego completo
		if (!gameCompleted)
		{
			gameOverMenu->checkInput();

			// Comprueba si se ha seleccionado algún item del menú
			switch (gameOverMenu->getItemSelected())
			{
			case 0: // YES
				postFade = 0;
				fade->activateFade();
				break;

			case 1: // NO
				postFade = 1;
				fade->activateFade();
				break;

			default:
				break;
			}
		}
	}

	// Comprueba los eventos que hay en la cola
	while (SDL_PollEvent(eventHandler) != 0)
	{
		// Evento de salida de la aplicación
		if (eventHandler->type == SDL_QUIT)
		{
			section->name = SECTION_PROG_QUIT;
			break;
		}
		else if (eventHandler->type == SDL_KEYDOWN && eventHandler->key.repeat == 0)
		{
			if (gameCompleted)
			{
				postFade = 1;
				fade->activateFade();
				JA_PlaySound(itemPickUpSound);
			}
		}
	}
}

// Dibuja los elementos de la pantalla de game over
void Game::renderGameOverScreen()
{
	// Prepara para empezar a dibujar en la textura de juego
	screen->start();

	// Limpia la pantalla
	screen->clean(bgColor);

	// Dibujo
	if (!gameCompleted)
	{ // Dibujo de haber perdido la partida
		gameOverSprite->render();
	}
	else
	{ // Dinujo de haber completado la partida
		gameOverEndSprite->render();
	}

	// Dibuja los objetos
	if (numPlayers == 1)
	{
		// Congratulations!!
		if (gameCompleted)
		{
			text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 8), lang->getText(50));
		}

		// Game Over
		textBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 6), lang->getText(43));

		// Your Score
		text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 3), lang->getText(44) + std::to_string(players[0]->getScore()));
	}
	else
	{
		// Congratulations!!
		if (gameCompleted)
		{
			text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 9), lang->getText(50));
		}

		// Game Over
		textBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 7), lang->getText(43));

		// Player1 Score
		text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 4), lang->getText(77) + std::to_string(players[0]->getScore()));

		// Player2 Score
		text->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 2), lang->getText(78) + std::to_string(players[1]->getScore()));
	}

	// Continue?
	if (!gameCompleted)
	{ // Solo dibuja el menu de continuar en el caso de no haber completado la partida
		text->writeCentered(199, PLAY_AREA_CENTER_Y + BLOCK * 3, lang->getText(45));
		gameOverMenu->render();
	}

	// Pinta el fade
	fade->render();

	// Vuelca el contenido del renderizador en pantalla
	screen->blit();
}

// Bucle para la pantalla de game over
void Game::runGameOverScreen()
{
	// Guarda los puntos
	saveScoreFile();

	// Sube la puntuación online
	sendOnlineScore();

	// Reinicia el menu
	gameOverMenu->reset();

	while ((section->subsection == SUBSECTION_GAME_GAMEOVER) && (section->name == SECTION_PROG_GAME))
	{
		updateGameOverScreen();
		renderGameOverScreen();
	}
}

// Indica si se puede crear una powerball
bool Game::canPowerBallBeCreated()
{
	if ((!powerBallEnabled) && (calculateScreenPower() > POWERBALL_SCREENPOWER_MINIMUM) && (powerBallCounter == 0))
	{
		return true;
	}

	return false;
}

// Calcula el poder actual de los globos en pantalla
int Game::calculateScreenPower()
{
	int power = 0;

	for (auto balloon : balloons)
	{
		if (balloon->isEnabled())
		{
			power += balloon->getPower();
		}
	}

	return power;
}

// Inicializa las variables que contienen puntos de ruta para mover objetos
void Game::initPaths()
{
	// Vector con los valores del seno para 360 grados
	float sin[360];
	for (int i = 0; i < 360; ++i)
	{
		sin[i] = SDL_sinf((float)i * 3.14f / 180.0f);
	}

	// Letrero de STAGE #
	const int firstPart = STAGE_COUNTER / 4; // 50
	const int secondPart = firstPart * 3;	 // 150
	const int centerPoint = PLAY_AREA_CENTER_Y - (BLOCK * 2);
	const int distance = (PLAY_AREA_BOTTOM) - (PLAY_AREA_CENTER_Y - 16);

	for (int i = 0; i < STAGE_COUNTER; ++i)
	{
		if (i < firstPart)
		{
			stageBitmapPath[i] = (sin[(int)((i * 1.8f) + 90)] * (distance) + centerPoint);
		}

		else if (i < secondPart)
		{
			stageBitmapPath[i] = (int)centerPoint;
		}

		else
		{
			stageBitmapPath[i] = (sin[(int)(((i - 149) * 1.8f) + 90)] * (centerPoint + 17) - 17);
		}
	}

	// Letrero de GetReady
	const int size = textNokiaBig2->lenght(lang->getText(75), -2);

	const float start1 = PLAY_AREA_LEFT - size;
	const float finish1 = PLAY_AREA_CENTER_X - (size / 2);

	const float start2 = finish1;
	const float finish2 = PLAY_AREA_RIGHT;

	const float distance1 = finish1 - start1;
	const float distance2 = finish2 - start2;

	for (int i = 0; i < STAGE_COUNTER; ++i)
	{
		if (i < firstPart)
		{
			getReadyBitmapPath[i] = sin[(int)(i * 1.8f)];
			getReadyBitmapPath[i] *= distance1;
			getReadyBitmapPath[i] -= size;
		}

		else if (i < secondPart)
		{
			getReadyBitmapPath[i] = (int)finish1;
		}

		else
		{
			getReadyBitmapPath[i] = sin[(int)((i - 150) * 1.8f)];
			getReadyBitmapPath[i] *= distance2;
			getReadyBitmapPath[i] += finish1;
		}
	}
}

// Actualiza el tramo final de juego, una vez completado
void Game::updateGameCompleted()
{
	if (gameCompleted)
	{
		gameCompletedCounter++;
	}

	if (gameCompletedCounter == GAME_COMPLETED_END)
	{
		section->subsection = SUBSECTION_GAME_GAMEOVER;
	}
}

// Actualiza las variables de ayuda
void Game::updateHelper()
{
	// Solo ofrece ayuda cuando la amenaza es elevada
	if (menaceCurrent > 15)
	{
		for (auto player : players)
		{
			if (player->getCoffees() == 0)
			{
				helper.needCoffee = true;
			}
			else
			{
				helper.needCoffee = false;
			}

			if (!player->isPowerUp())
			{
				helper.needCoffeeMachine = true;
			}
			else
			{
				helper.needCoffeeMachine = false;
			}
		}
	}
	else
	{
		helper.needCoffee = false;
		helper.needCoffeeMachine = false;
	}
}

// Comprueba si todos los jugadores han muerto
bool Game::allPlayersAreDead()
{
	bool success = true;
	for (auto player : players)
	{
		success &= (!player->isAlive());
	}

	return success;
}

// Comprueba los eventos que hay en cola
void Game::checkEvents()
{
	while (SDL_PollEvent(eventHandler) != 0)
	{
		// Evento de salida de la aplicación
		if (eventHandler->type == SDL_QUIT)
		{
			section->name = SECTION_PROG_QUIT;
			break;
		}

		else if (eventHandler->type == SDL_WINDOWEVENT)
		{
			if (eventHandler->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
			{
				section->subsection = SUBSECTION_GAME_PAUSE;
			}
		}
	}
}

// Carga las animaciones
void Game::loadAnimations(std::string filePath, std::vector<std::string> *buffer)
{
	std::ifstream file(filePath);
	std::string line;

	if (file)
	{
		if (options->console)
		{
			std::cout << "Animation loaded: " << filePath.substr(filePath.find_last_of("\\/") + 1).c_str() << std::endl;
		}
		while (std::getline(file, line))
		{
			buffer->push_back(line);
		}
		file.close();
	}
}

// Elimina todos los objetos contenidos en vectores
void Game::deleteAllVectorObjects()
{
	for (auto player : players)
	{
		delete player;
	};
	players.clear();

	for (auto ballon : balloons)
	{
		delete ballon;
	};
	balloons.clear();

	for (auto bullet : bullets)
	{
		delete bullet;
	};
	bullets.clear();

	for (auto item : items)
	{
		delete item;
	};
	items.clear();

	for (auto smartSprite : smartSprites)
	{
		delete smartSprite;
	};
	smartSprites.clear();
}

// Recarga las texturas
void Game::reloadTextures()
{
	for (auto texture : itemTextures)
	{
		texture->reLoad();
	}

	for (auto texture : balloonTextures)
	{
		texture->reLoad();
	}

	for (auto texture : player1Textures)
	{
		texture->reLoad();
	}

	for (auto texture : player2Textures)
	{
		texture->reLoad();
	}

	bulletTexture->reLoad();
	gameBuildingsTexture->reLoad();
	gameCloudsTexture->reLoad();
	gameGrassTexture->reLoad();
	gamePowerMeterTexture->reLoad();
	gameSkyColorsTexture->reLoad();
	gameTextTexture->reLoad();
}