#include "game.h"

// Constructor
Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang, Input *input, bool demo, options_t *options)
{
	// Copia los punteros
	mRenderer = renderer;
	mScreen = screen;
	this->mAsset = mAsset;
	mLang = lang;
	mInput = input;
	mOptions = options;
	mOnePlayerControl = mOptions->input[0].deviceType;

	// Pasa variables
	mDemo.enabled = demo;
	mNumPlayers = numPlayers;
	mCurrentStage = currentStage;
	mLastStageReached = currentStage;
	if (mNumPlayers == 1)
	{
		mOptions->input[0].deviceType = INPUT_USE_ANY;
	}
	mDifficulty = mOptions->difficulty;

	// Crea los objetos
	// Vector de jugadores
	if (mNumPlayers == 1)
	{
		Player *player = new Player(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer1Legs, mTexturePlayer1Body, mTexturePlayer1Head, mTexturePlayer1Death, mRenderer);
		players.push_back(player);
	}

	else if (mNumPlayers == 2)
	{
		Player *player1 = new Player((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((0 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer1Legs, mTexturePlayer1Body, mTexturePlayer1Head, mTexturePlayer1Death, mRenderer);
		Player *player2 = new Player((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((1 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer2Legs, mTexturePlayer2Body, mTexturePlayer2Head, mTexturePlayer2Death, mRenderer);
		players.push_back(player1);
		players.push_back(player2);
	}

	mTextureBalloon = new LTexture(mRenderer, mAsset->get("balloon.png"));
	mTextureBullet = new LTexture(mRenderer, mAsset->get("bullet.png"));
	mTextureGameBG = new LTexture(mRenderer, mAsset->get("game_bg.png"));
	mTextureGameText = new LTexture(mRenderer, mAsset->get("game_text.png"));
	mTextureItems = new LTexture(mRenderer, mAsset->get("items.png"));

	mTexturePlayer1Head = new LTexture(mRenderer, mAsset->get("player1_head.png"));
	mTexturePlayer1Body = new LTexture(mRenderer, mAsset->get("player1_body.png"));
	mTexturePlayer1Legs = new LTexture(mRenderer, mAsset->get("player1_legs.png"));
	mTexturePlayer1Death = new LTexture(mRenderer, mAsset->get("player1_death.png"));

	mTexturePlayer2Head = new LTexture(mRenderer, mAsset->get("player2_head.png"));
	mTexturePlayer2Body = new LTexture(mRenderer, mAsset->get("player2_body.png"));
	mTexturePlayer2Legs = new LTexture(mRenderer, mAsset->get("player2_legs.png"));
	mTexturePlayer2Death = new LTexture(mRenderer, mAsset->get("player2_death.png"));

	mText = new Text(mAsset->get("smb2.png"), mAsset->get("smb2.txt"), mRenderer);
	mTextScoreBoard = new Text(mAsset->get("8bithud.png"), mAsset->get("8bithud.txt"), mRenderer);
	mTextBig = new Text(mAsset->get("smb2_big.png"), mAsset->get("smb2_big.txt"), mRenderer);
	mTextNokia2 = new Text(mAsset->get("nokia2.png"), mAsset->get("nokia2.txt"), mRenderer);
	mTextNokiaBig2 = new Text(mAsset->get("nokia_big2.png"), mAsset->get("nokia_big2.txt"), mRenderer);

	mMenuGameOver = new Menu(mRenderer, mAsset, mInput);
	mMenuPause = new Menu(mRenderer, mAsset, mInput);

	mFade = new Fade(mRenderer);
	mEventHandler = new SDL_Event();

	mClouds1a = new MovingSprite(0, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
	mClouds1b = new MovingSprite(256, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
	mClouds2a = new MovingSprite(0, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
	mClouds2b = new MovingSprite(256, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);

	m1000Bitmap = new SmartSprite(mTextureGameText, mRenderer);
	m2500Bitmap = new SmartSprite(mTextureGameText, mRenderer);
	m5000Bitmap = new SmartSprite(mTextureGameText, mRenderer);

	mSpriteBackground = new Sprite(0, 0, GAME_WIDTH, GAME_HEIGHT, mTextureGameBG, mRenderer);
	mSpriteGetReady = new Sprite(0, PLAY_AREA_CENTER_Y - 10, 109, 20, mTextureGameText, mRenderer);
	mSpriteGradient = new Sprite(0, 0, GAME_WIDTH, GAME_HEIGHT, mTextureGameBG, mRenderer);
	mSpriteGrass = new Sprite(0, 85, GAME_WIDTH, 6, mTextureGameBG, mRenderer);
	mSpritePowerMeter = new Sprite(PLAY_AREA_CENTER_X - 20, 170, 40, 8, mTextureGameBG, mRenderer);
	mSpriteScoreBoard = new Sprite(0, 160, GAME_WIDTH, 32, mTextureGameBG, mRenderer);
}

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

	mOptions->input[0].deviceType = mOnePlayerControl;

	mRenderer = nullptr;
	mScreen = nullptr;
	mAsset = nullptr;
	mLang = nullptr;
	mInput = nullptr;

	for (auto player : players)
	{
		delete player;
	};

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

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

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

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

	mTextureBalloon->unload();
	delete mTextureBalloon;
	mTextureBalloon = nullptr;

	mTextureBullet->unload();
	delete mTextureBullet;
	mTextureBullet = nullptr;

	mTextureGameBG->unload();
	delete mTextureGameBG;
	mTextureGameBG = nullptr;

	mTextureGameText->unload();
	delete mTextureGameText;
	mTextureGameText = nullptr;

	mTextureItems->unload();
	delete mTextureItems;
	mTextureItems = nullptr;

	mTexturePlayer1Head->unload();
	delete mTexturePlayer1Head;
	mTexturePlayer1Head = nullptr;

	mTexturePlayer1Body->unload();
	delete mTexturePlayer1Body;
	mTexturePlayer1Body = nullptr;

	mTexturePlayer1Death->unload();
	delete mTexturePlayer1Death;
	mTexturePlayer1Death = nullptr;

	mTexturePlayer1Legs->unload();
	delete mTexturePlayer1Legs;
	mTexturePlayer1Legs = nullptr;

	mTexturePlayer2Head->unload();
	delete mTexturePlayer2Head;
	mTexturePlayer2Head = nullptr;

	mTexturePlayer2Body->unload();
	delete mTexturePlayer2Body;
	mTexturePlayer2Body = nullptr;

	mTexturePlayer2Death->unload();
	delete mTexturePlayer2Death;
	mTexturePlayer2Death = nullptr;

	mTexturePlayer2Legs->unload();
	delete mTexturePlayer2Legs;
	mTexturePlayer2Legs = nullptr;

	delete mText;
	mText = nullptr;

	delete mTextBig;
	mTextBig = nullptr;

	delete mTextScoreBoard;
	mTextScoreBoard = nullptr;

	delete mTextNokia2;
	mTextNokia2 = nullptr;

	delete mTextNokiaBig2;
	mTextNokiaBig2 = nullptr;

	delete mMenuGameOver;
	mMenuGameOver = nullptr;

	delete mMenuPause;
	mMenuPause = nullptr;

	delete mFade;
	mFade = nullptr;

	delete mEventHandler;
	mEventHandler = nullptr;

	delete mClouds1a;
	mClouds1a = nullptr;

	delete mClouds1b;
	mClouds1b = nullptr;

	delete mClouds2a;
	mClouds2a = nullptr;

	delete mClouds2b;
	mClouds2b = nullptr;

	delete m1000Bitmap;
	m1000Bitmap = nullptr;

	delete m2500Bitmap;
	m2500Bitmap = nullptr;

	delete m5000Bitmap;
	m5000Bitmap = nullptr;

	delete mSpriteBackground;
	mSpriteBackground = nullptr;

	delete mSpriteGetReady;
	mSpriteGetReady = nullptr;

	delete mSpriteGradient;
	mSpriteGradient = nullptr;

	delete mSpriteGrass;
	mSpriteGrass = nullptr;

	delete mSpritePowerMeter;
	mSpritePowerMeter = nullptr;

	delete mSpriteScoreBoard;
	mSpriteScoreBoard = nullptr;

	JA_DeleteSound(mSoundBalloon);
	JA_DeleteSound(mSoundBullet);
	JA_DeleteSound(mSoundPlayerCollision);
	JA_DeleteSound(mSoundHiScore);
	JA_DeleteSound(mSoundItemDrop);
	JA_DeleteSound(mSoundItemPickup);
	JA_DeleteSound(mSoundCoffeeOut);
	JA_DeleteSound(mSoundStageChange);
	JA_DeleteSound(mSoundBubble1);
	JA_DeleteSound(mSoundBubble2);
	JA_DeleteSound(mSoundBubble3);
	JA_DeleteSound(mSoundBubble4);
	JA_DeleteSound(mSoundClock);
	JA_DeleteSound(mSoundPowerBall);
	JA_DeleteSound(mSoundCollision);

	JA_DeleteMusic(mMusicPlaying);
}

// Inicializa el vector con los valores del seno
void Game::initSin()
{
	// Vector con los valores del seno para 360 grados
	for (int i = 0; i < 360; i++)
	{
		mSin[i] = SDL_sinf((float)i * 3.14f / 180.0f);
	}
}

// Inicializa las variables necesarias para la sección 'Game'
void Game::init()
{
	// Carga los recursos
	loadMedia();

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

	mTicks = 0;
	mTicksSpeed = 15;

	// Inicializa las variables
	switch (mDifficulty)
	{
	case DIFFICULTY_EASY:
		mDefaultEnemySpeed = BALLOON_SPEED_1;
		mDifficultyScoreMultiplier = 0.5f;
		break;

	case DIFFICULTY_NORMAL:
		mDefaultEnemySpeed = BALLOON_SPEED_1;
		mDifficultyScoreMultiplier = 1.0f;
		break;

	case DIFFICULTY_HARD:
		mDefaultEnemySpeed = BALLOON_SPEED_5;
		mDifficultyScoreMultiplier = 1.5f;
		break;

	default:
		break;
	}
	mGameCompleted = false;
	mGameCompletedCounter = 0;
	mSection.name = PROG_SECTION_GAME;
	mSection.subsection = GAME_SECTION_PLAY_1P;
	mMenaceCurrent = 0;
	mMenaceThreshold = 0;
	mHiScoreAchieved = false;
	// mCurrentStage = 0;
	mStageBitmapCounter = STAGE_COUNTER;
	mDeathCounter = DEATH_COUNTER;
	mTimeStopped = false;
	mTimeStoppedCounter = 0;
	mCounter = 0;
	mLastEnemyDeploy = 0;
	mEnemyDeployCounter = 0;
	mEnemySpeed = mDefaultEnemySpeed;
	mEffect.flash = false;
	mEffect.shake = false;
	mEffect.shakeCounter = SHAKE_COUNTER;
	mHelper.needCoffee = false;
	mHelper.needCoffeeMachine = false;
	mHelper.needPowerBall = false;
	mHelper.counter = HELP_COUNTER;
	mHelper.itemPoints1Odds = ITEM_POINTS_1_DISK_ODDS;
	mHelper.itemPoints2Odds = ITEM_POINTS_2_GAVINA_ODDS;
	mHelper.itemPoints3Odds = ITEM_POINTS_3_PACMAR_ODDS;
	mHelper.itemClockOdds = ITEM_CLOCK_ODDS;
	mHelper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
	mHelper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
	mPowerBallEnabled = false;
	mPowerBallCounter = 0;
	mCoffeeMachineEnabled = false;
	mPostFade = 0;
	// mLastStageReached = 0;

	if (mDemo.enabled)
	{
		const int num = rand() % 2;
		if (num == 0)
		{
			mBalloonsPopped = 1000;
			mCurrentStage = 3;
		}
		else
		{
			mBalloonsPopped = 1800;
			mCurrentStage = 6;
		}
	}

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

	// Mas variables
	mBalloonsPopped = 0;
	for (int i = 0; i < mCurrentStage; ++i)
	{
		mBalloonsPopped += mStage[i].powerToComplete;
	}

	// Modo debug
	mDebug.enabled = false;
	mDebug.enemySet = 0;
	mDebug.gradR = mDebug.gradG = mDebug.gradB = 0;

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

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

	// Inicializa el objeto con el menu de pausa
	mMenuPause->setName("PAUSE");
	mMenuPause->setPos(0, 12 * BLOCK);
	mMenuPause->setBackgroundType(MENU_BACKGROUND_SOLID);
	mMenuPause->addItem(mLang->getText(46), 2);
	mMenuPause->addItem(mLang->getText(47), 0);
	mMenuPause->setDefaultActionWhenCancel(0);
	mMenuPause->setBackgroundColor({0x29, 0x39, 0x41}, 240);
	mMenuPause->setSelectorColor({0xFF, 0x7A, 0x00}, 255);
	mMenuPause->setSelectorTextColor({0xFF, 0xFF, 0xFF});
	mMenuPause->centerMenuOnX(SCREEN_CENTER_X);
	mMenuPause->centerMenuElementsOnX();

	// Inicializa el objeto con el menu de la pantalla de game over
	mMenuGameOver->setName("GAME OVER");
	mMenuGameOver->setPos(0, PLAY_AREA_CENTER_Y + BLOCK * 4);
	mMenuGameOver->setBackgroundType(MENU_BACKGROUND_TRANSPARENT);
	mMenuGameOver->addItem(mLang->getText(48), 2);
	mMenuGameOver->addItem(mLang->getText(49));
	mMenuGameOver->setDefaultActionWhenCancel(1);
	mMenuGameOver->setBackgroundColor({0, 0, 0}, 255);
	mMenuGameOver->setSelectorColor({0x54, 0x6e, 0x7a}, 255);
	mMenuGameOver->setSelectorColor({0x54, 0x6e, 0x7a}, 0);
	mMenuGameOver->setSelectorTextColor({0xFF, 0xFF, 0xFF});
	mMenuGameOver->setSelectorTextColor({0xFF, 0xF1, 0x76});
	mMenuGameOver->setSelectorTextColor({0xFF, 0x7A, 0x00});
	mMenuGameOver->centerMenuOnX(SCREEN_CENTER_X);
	mMenuGameOver->centerMenuElementsOnX();

	// Sprites
	mClouds1a->setSpriteClip(256, 0, 256, 52);
	mClouds1b->setSpriteClip(256, 0, 256, 52);
	mClouds2a->setSpriteClip(256, 52, 256, 32);
	mClouds2b->setSpriteClip(256, 52, 256, 32);

	mSpriteGrass->setPosY(154);
	mSpriteScoreBoard->setSpriteClip(0, 160, 256, 32);
	mSpritePowerMeter->setSpriteClip(256, 192 - 8, 40, 8);

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

	// Inicializa el bitmap de GetReady!
	mSpriteGetReady->setSpriteClip(0, 0, 109, 20);

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

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

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

	// Los fondos
	mGradientRect[0] = {0, 192, GAME_WIDTH, GAME_HEIGHT};
	mGradientRect[1] = {256, 192, GAME_WIDTH, GAME_HEIGHT};
	mGradientRect[2] = {0, 384, GAME_WIDTH, GAME_HEIGHT};
	mGradientRect[3] = {256, 384, GAME_WIDTH, GAME_HEIGHT};
}

// Carga los recursos necesarios para la sección 'Game'
bool Game::loadMedia()
{
	bool success = true;

	// Sonidos
	mSoundBalloon = JA_LoadSound(mAsset->get("balloon.wav").c_str());
	mSoundBubble1 = JA_LoadSound(mAsset->get("bubble1.wav").c_str());
	mSoundBubble2 = JA_LoadSound(mAsset->get("bubble2.wav").c_str());
	mSoundBubble3 = JA_LoadSound(mAsset->get("bubble3.wav").c_str());
	mSoundBubble4 = JA_LoadSound(mAsset->get("bubble4.wav").c_str());
	mSoundBullet = JA_LoadSound(mAsset->get("bullet.wav").c_str());
	mSoundClock = JA_LoadSound(mAsset->get("clock.wav").c_str());
	mSoundCoffeeOut = JA_LoadSound(mAsset->get("coffeeout.wav").c_str());
	mSoundHiScore = JA_LoadSound(mAsset->get("hiscore.wav").c_str());
	mSoundItemDrop = JA_LoadSound(mAsset->get("itemdrop.wav").c_str());
	mSoundItemPickup = JA_LoadSound(mAsset->get("itempickup.wav").c_str());
	mSoundPlayerCollision = JA_LoadSound(mAsset->get("player_collision.wav").c_str());
	mSoundPowerBall = JA_LoadSound(mAsset->get("powerball.wav").c_str());
	mSoundStageChange = JA_LoadSound(mAsset->get("stage_change.wav").c_str());
	mSoundCollision = JA_LoadSound(mAsset->get("title.wav").c_str());

	// Musicas
	mMusicPlaying = JA_LoadMusic(mAsset->get("playing.ogg").c_str());

	return success;
}

// Carga el fichero de puntos
bool Game::loadScoreFile()
{
	// Indicador de éxito en la carga
	bool success = true;
	const std::string p = mAsset->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)
	{
		printf("Warning: Unable to open %s file\n", filename.c_str());

		// Creamos el fichero para escritura
		file = SDL_RWFromFile(p.c_str(), "w+b");
		if (file != nullptr)
		{
			printf("New file (%s) created!\n", filename.c_str());

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

			// Cerramos el fichero
			SDL_RWclose(file);
		}
		else
		{
			printf("Error: Unable to create file %s\n", filename.c_str());
			success = false;
		}
	}
	// El fichero existe
	else
	{
		// Cargamos los datos
		printf("Reading file %s\n", filename.c_str());
		for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
			SDL_RWread(file, &mScoreDataFile[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 (mScoreDataFile[0] == 0)
	{
		mHiScore = 10000;
	}
	// Comprueba el checksum para ver si se ha modificado el fichero
	else if (mScoreDataFile[0] % 43 == mScoreDataFile[1])
	{
		mHiScore = mScoreDataFile[0];
	}
	else
	{
		mHiScore = 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 = mAsset->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)
	{
		printf("Warning: Unable to open %s file\n", filename.c_str());

		// Creamos el fichero para escritura
		file = SDL_RWFromFile(p.c_str(), "w+b");
		if (file != nullptr)
		{
			printf("New file (%s) created!\n", filename.c_str());

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

			// Cerramos el fichero
			SDL_RWclose(file);
		}
		else
		{
			printf("Error: Unable to create file %s\n", filename.c_str());
			success = false;
		}
	}
	// El fichero existe
	else
	{
		// Cargamos los datos
		printf("Reading file %s\n", filename.c_str());
		for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
			SDL_RWread(file, &mDemo.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 = mAsset->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, &mScoreDataFile[i], sizeof(Uint32), 1);
		}

		printf("Writing file %s\n", filename.c_str());

		// Cerramos el fichero
		SDL_RWclose(file);
	}
	else
	{
		printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError());
	}
	return success;
}

// Guarda el fichero de datos para la demo
bool Game::saveDemoFile()
{
	bool success = true;
	const std::string p = mAsset->get("demo.bin");
	const std::string filename = p.substr(p.find_last_of("\\/") + 1);
	if (mDemo.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, &mDemo.dataFile[i], sizeof(demoKeys_t), 1);
			}

			printf("Writing file %s\n", filename.c_str());

			// Cerramos el fichero
			SDL_RWclose(file);
		}
		else
		{
			printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError());
		}
	}
	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++)
	{
		mEnemyFormation[i].numberOfEnemies = 0;
		for (int j = 0; j < MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION; j++)
		{
			mEnemyFormation[i].init[j].x = 0;
			mEnemyFormation[i].init[j].y = 0;
			mEnemyFormation[i].init[j].velX = 0;
			mEnemyFormation[i].init[j].kind = 0;
			mEnemyFormation[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;
	mEnemyFormation[j].numberOfEnemies = 2;
	incX = x4_100;
	incTime = 0;
	for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
	{
		mEnemyFormation[j].init[i].x = x4_0 + (i * incX);
		mEnemyFormation[j].init[i].y = y4;
		mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
		mEnemyFormation[j].init[i].kind = BALLOON_4;
		mEnemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	// STAGE 10
	mStage[9].number = 10;
	mStage[9].currentPower = 0;
	mStage[9].powerToComplete = 950;
	mStage[9].minMenace = 7 + (4 * 7);
	mStage[9].maxMenace = 7 + (4 * 10);
	mStage[9].enemyPool = &mEnemyPool[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 (mEnemyDeployCounter == 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
			mEnemyDeployCounter = 50;
		}
		else
		{
			// Decrementa el contador de despliegues enemigos de la PowerBall
			mPowerBallCounter > 0 ? mPowerBallCounter-- : mPowerBallCounter = 0;

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

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

			mLastEnemyDeploy = set;

			if (mDebug.enabled)
				set = mDebug.enemySet;

			Uint8 numEnemies = mStage[mCurrentStage].enemyPool->set[set]->numberOfEnemies;
			for (int i = 0; i < numEnemies; i++)
				createNewBalloon(mStage[mCurrentStage].enemyPool->set[set]->init[i].x,
								 mStage[mCurrentStage].enemyPool->set[set]->init[i].y,
								 mStage[mCurrentStage].enemyPool->set[set]->init[i].kind,
								 mStage[mCurrentStage].enemyPool->set[set]->init[i].velX,
								 mEnemySpeed,
								 mStage[mCurrentStage].enemyPool->set[set]->init[i].creationCounter,
								 mTextureBalloon);

			mEnemyDeployCounter = 300;
		}
	}
}

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

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

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

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

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

// Transforma un valor numérico en una cadena de 6 cifras
std::string Game::updateScoreText(Uint32 num)
{
	// return (std::to_string(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()
{
	mSpriteScoreBoard->render();

	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
	mTextScoreBoard->writeCentered(offsetLeft, offset1, mLang->getText(53));
	mTextScoreBoard->writeCentered(offsetLeft, offset2, updateScoreText(players[0]->getScore()));

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

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

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

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

	// STAGE
	mTextScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset1, mLang->getText(57) + std::to_string(mStage[mCurrentStage].number));

	// POWER
	mSpritePowerMeter->setPosY(offset2);
	mSpritePowerMeter->setSpriteClip(256, 184, 40, 8);
	mSpritePowerMeter->render();
	const float percent = (mStage[mCurrentStage].currentPower * 40.0f) / mStage[mCurrentStage].powerToComplete;
	mSpritePowerMeter->setSpriteClip(296, 184, (int)percent, 8);
	mSpritePowerMeter->render();

	// HI-SCORE
	mTextScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset3, mLang->getText(56));
	mTextScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset4, updateScoreText(mHiScore));
}

// Actualiza las variables del jugador
void Game::updatePlayer()
{
	for (auto player : players)
	// for (int i = 0; i < mNumPlayers; i++)
	{
		player->update();

		// Comprueba la colisión entre el jugador y los globos
		if (checkPlayerBalloonCollision(player))
		{
			if (player->isAlive())
			{
				if (mDemo.enabled)
				{
					mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS};
				}
				else
				{
					killPlayer(player);
				}
			}
		}

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

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

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

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

// Actualiza el estado de muerte
void Game::updateDeath()
{
	// Comprueba si todos los jugadores estan muertos
	bool allAreDead = true;
	for (auto player : players)
	// for (int i = 0; i < mNumPlayers; i++)
	{
		allAreDead &= (!player->isAlive());

		if (!player->isAlive())
		{
			// Animación
			if ((player->getDeathCounter() / 5) % 4 == 0)
			{
				smartSprites[player->mDeathIndex]->setSpriteClip(24 * 0, 24, 24, 24);
			}
			else if ((player->getDeathCounter() / 5) % 4 == 1)
			{
				smartSprites[player->mDeathIndex]->setSpriteClip(24 * 1, 24, 24, 24);
			}
			else if ((player->getDeathCounter() / 5) % 4 == 2)
			{
				smartSprites[player->mDeathIndex]->setSpriteClip(24 * 2, 24, 24, 24);
			}
			else if ((player->getDeathCounter() / 5) % 4 == 3)
			{
				smartSprites[player->mDeathIndex]->setSpriteClip(24 * 3, 24, 24, 24);
			}

			// Rebote en los laterales
			if (smartSprites[player->mDeathIndex]->getVelX() > 0)
			{
				if (smartSprites[player->mDeathIndex]->getPosX() > (GAME_WIDTH - smartSprites[player->mDeathIndex]->getWidth()))
				{
					smartSprites[player->mDeathIndex]->setPosX(GAME_WIDTH - smartSprites[player->mDeathIndex]->getWidth());
					smartSprites[player->mDeathIndex]->setVelX(smartSprites[player->mDeathIndex]->getVelX() * (-1));
					smartSprites[player->mDeathIndex]->setDestX(smartSprites[player->mDeathIndex]->getDestX() * (-1));
				}
			}
			else
			{
				if (smartSprites[player->mDeathIndex]->getPosX() < 0)
				{
					smartSprites[player->mDeathIndex]->setPosX(0);
					smartSprites[player->mDeathIndex]->setVelX(smartSprites[player->mDeathIndex]->getVelX() * (-1));
					smartSprites[player->mDeathIndex]->setDestX(smartSprites[player->mDeathIndex]->getDestX() * (-1));
				}
			}
		}
	}

	if (allAreDead)
	{
		if (mDeathCounter > 0)
		{
			mDeathCounter--;
			if ((mDeathCounter == 250) || (mDeathCounter == 200) || (mDeathCounter == 180) || (mDeathCounter == 120) || (mDeathCounter == 60))
			{
				Uint8 sound = rand() % 4;
				switch (sound)
				{
				case 0:
					JA_PlaySound(mSoundBubble1, 0);
					break;
				case 1:
					JA_PlaySound(mSoundBubble2, 0);
					break;
				case 2:
					JA_PlaySound(mSoundBubble3, 0);
					break;
				case 3:
					JA_PlaySound(mSoundBubble4, 0);
					break;

				default:
					break;
				}
			}
		}
		else
		{
			mSection.subsection = GAME_SECTION_GAMEOVER;
		}
	}
}

// Renderiza el fade final cuando se acaba la partida
void Game::renderDeathFade(int counter)
// Counter debe ir de 0 a 150
{
	SDL_SetRenderDrawColor(mRenderer, 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 = GAME_WIDTH;
			if (i == 0)
				rect[i].h = h;
			else
				rect[i].h = std::max(rect[i - 1].h - 3, 0);
			SDL_RenderFillRect(mRenderer, &rect[i]);
		}
	}
	else
	{
		SDL_Rect rect = {0, 0, GAME_WIDTH, GAME_HEIGHT};
		SDL_RenderFillRect(mRenderer, &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::createNewBalloon(float x, int y, Uint8 kind, float velx, float speed, Uint16 creationtimer, LTexture *texture)
{
	Balloon *b = new Balloon(x, y, kind, velx, speed, creationtimer, texture, mRenderer);
	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 x[3] = {left, center, right};
	const int posX = x[rand() % 3];

	Balloon *b = new Balloon(posX, posY, POWER_BALL, BALLOON_VELX_POSITIVE * (((rand() % 2) * 2) - 1), mEnemySpeed, 100, mTextureBalloon, mRenderer);
	balloons.push_back(b);

	mPowerBallEnabled = true;
	mPowerBallCounter = POWERBALL_COUNTER;
}

// Establece la velocidad de los globos
void Game::setBalloonSpeed(float speed)
{
	for (auto balloon : balloons)

	// for (int i = 0; i < MAX_BALLOONS; i++)
	{
		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 (mDifficulty == DIFFICULTY_NORMAL)
	{
		if (mEnemySpeed == BALLOON_SPEED_1)
			mEnemySpeed = BALLOON_SPEED_2;
		else if (mEnemySpeed == BALLOON_SPEED_2)
			mEnemySpeed = BALLOON_SPEED_3;
		else if (mEnemySpeed == BALLOON_SPEED_3)
			mEnemySpeed = BALLOON_SPEED_4;
		else if (mEnemySpeed == BALLOON_SPEED_4)
			mEnemySpeed = BALLOON_SPEED_5;

		setBalloonSpeed(mEnemySpeed);
	}
}

// Decrementa la velocidad de los globos
void Game::decBalloonSpeed()
{
	// La velocidad solo se decrementa en el modo normal
	if (mDifficulty == DIFFICULTY_NORMAL)
	{
		if (mEnemySpeed == BALLOON_SPEED_5)
			mEnemySpeed = BALLOON_SPEED_4;
		else if (mEnemySpeed == BALLOON_SPEED_4)
			mEnemySpeed = BALLOON_SPEED_3;
		else if (mEnemySpeed == BALLOON_SPEED_3)
			mEnemySpeed = BALLOON_SPEED_2;
		else if (mEnemySpeed == BALLOON_SPEED_2)
			mEnemySpeed = BALLOON_SPEED_1;

		setBalloonSpeed(mEnemySpeed);
	}
}

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

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

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

	else if (mEnemySpeed == 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);
	mBalloonsPopped++;

	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();
		mPowerBallEnabled = false;
		mEnemyDeployCounter = 20;
		break;

	// En cualquier otro caso, crea dos globos de un tipo inferior
	default:
		Balloon *b1 = new Balloon(0, balloon->getPosY(), balloon->getKind() - 1, BALLOON_VELX_NEGATIVE, mEnemySpeed, 0, mTextureBalloon, mRenderer);
		balloons.push_back(b1);
		b1->allignTo(balloon->getPosX() + (balloon->getWidth() / 2));
		if (b1->getClass() == BALLOON_CLASS)
		{
			b1->setVelY(-2.50f);
		}
		else if (b1->getClass() == HEXAGON_CLASS)
		{
			b1->setVelY(BALLOON_VELX_NEGATIVE);
		}

		Balloon *b2 = new Balloon(0, balloon->getPosY(), balloon->getKind() - 1, BALLOON_VELX_POSITIVE, mEnemySpeed, 0, mTextureBalloon, mRenderer);
		balloons.push_back(b2);
		b2->allignTo(balloon->getPosX() + (balloon->getWidth() / 2));
		if (b2->getClass() == BALLOON_CLASS)
		{
			b2->setVelY(-2.50f);
		}
		else if (b2->getClass() == HEXAGON_CLASS)
		{
			b2->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() * mDifficultyScoreMultiplier));
	}
	updateHiScore();

	// Aumenta el poder de la fase
	increaseStageCurrentPower(power);
	mBalloonsPopped += 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(mSoundBalloon);
}

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

	mEnemyDeployCounter = 255;
	JA_PlaySound(mSoundPowerBall);
	mEffect.flash = true;
	mEffect.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;
}

// 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)
	// for (int i = 0; i < MAX_ITEMS; i++)
	{
		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) - (m1000Bitmap->getWidth() / 2), player->getPosY(), m1000Bitmap);
					JA_PlaySound(mSoundItemPickup);
					break;
				case ITEM_POINTS_2_GAVINA:
					player->addScore(2500);
					updateHiScore();
					createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (m2500Bitmap->getWidth() / 2), player->getPosY(), m2500Bitmap);
					JA_PlaySound(mSoundItemPickup);
					break;
				case ITEM_POINTS_3_PACMAR:
					player->addScore(5000);
					updateHiScore();
					createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), player->getPosY(), m5000Bitmap);
					JA_PlaySound(mSoundItemPickup);
					break;
				case ITEM_CLOCK:
					enableTimeStopItem();
					JA_PlaySound(mSoundItemPickup);
					break;
				case ITEM_COFFEE:
					if (player->getCoffees() == 2)
					{
						player->addScore(5000);
						updateHiScore();
						createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), player->getPosY(), m5000Bitmap);
					}
					player->giveExtraHit();
					JA_PlaySound(mSoundItemPickup);
					break;
				case ITEM_COFFEE_MACHINE:
					player->setPowerUp(true);
					JA_PlaySound(mSoundItemPickup);
					mCoffeeMachineEnabled = false;
					break;

				default:
					break;
				}
				item->erase();
			}
		}
	}
}

// Comprueba y procesa la colisión entre las balas y los globos
void Game::checkBulletBalloonCollision()
{
	for (auto balloon : balloons)
	{
		for (auto bullet : bullets)
		{
			if (balloon->isEnabled() && (!balloon->isInvulnerable()) && bullet->isActive())
			{
				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() * mDifficultyScoreMultiplier));
					updateHiScore();

					// Explota el globo
					popBalloon(balloon);

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

					// Destruye la bala
					delete bullet;

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

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

// Pinta las balas activas
void Game::renderBullets()
{
	for (auto bullet : bullets)
	{
		if (bullet->isActive())
		{
			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, mTextureBullet, mRenderer);
	bullets.push_back(b);
}

// Actualiza los items
void Game::updateItems()
{
	for (auto item : items)
	{
		item->update();
		if (item->floorCollision())
		{
			JA_PlaySound(mSoundCollision);
			mEffect.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 < mHelper.itemPoints1Odds)
			return ITEM_POINTS_1_DISK;
		break;

	case 1:
		if (luckyNumber < mHelper.itemPoints2Odds)
			return ITEM_POINTS_2_GAVINA;
		break;

	case 2:
		if (luckyNumber < mHelper.itemPoints3Odds)
			return ITEM_POINTS_3_PACMAR;
		break;

	case 3:
		if (luckyNumber < mHelper.itemClockOdds)
			return ITEM_CLOCK;
		break;

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

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

	default:
		break;
	}

	return NO_KIND;
}

// Crea un objeto item
void Game::createItem(LTexture *texture, SDL_Renderer *renderer, Uint8 type, float x, float y)
{
	Item *i = new Item(texture, renderer, type, x, y);
	items.push_back(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, mRenderer);
	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);
}

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

		mEffect.flash = false;
	}
}

// Actualiza el efecto de agitar la pantalla
void Game::updateShakeEffect()
{
	if (mEffect.shake)
	{
		if (mEffect.shakeCounter > 0)
		{
			mEffect.shakeCounter--;
		}
		else
		{
			mEffect.shake = false;
			mEffect.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(nullptr, mRenderer);
	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(GAME_HEIGHT + 1);
	ss->setEnabled(true);
	ss->setEnabledCounter(1);
	ss->setSpriteClip(80, 16, 16, 16);
	ss->setRotate(true);
	ss->setRotateSpeed(10);
	ss->setRotateAmount(90.0);
}

// Crea un SmartSprite para arrojar al jugador al morir
void Game::throwPlayer(int x, int y, Player *player)
{
	const int sentit = ((rand() % 2) ? 1 : -1);

	//player->mDeathIndex = getSmartSpriteFreeIndex();

	SmartSprite *ss = new SmartSprite(nullptr, mRenderer);
	smartSprites.push_back(ss);

	ss->setTexture(player->getDeadTexture());
	ss->setPosX(x);
	ss->setPosY(y);
	ss->setWidth(24);
	ss->setHeight(24);
	ss->setVelX(2.0f * sentit);
	ss->setVelY(-5.0f);
	ss->setAccelX(0.0f);
	ss->setAccelY(0.2f);
	ss->setDestX(GAME_WIDTH * sentit);
	ss->setDestY(GAME_HEIGHT + 1);
	ss->setEnabled(true);
	ss->setEnabledCounter(1);
	ss->setSpriteClip(0, 0, 24, 24);
}

// 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(mSoundCoffeeOut);
		}
		else
		{
			JA_PauseMusic();
			stopAllBalloons(10);
			JA_PlaySound(mSoundPlayerCollision);
			shakeScreen();
			SDL_Delay(500);
			JA_PlaySound(mSoundCoffeeOut);
			throwPlayer(player->getPosX(), player->getPosY(), player);
			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()
{
	mMenaceCurrent = 0;
	for (auto balloon:balloons)
	{
		if (balloon->isEnabled())
		{
			mMenaceCurrent += balloon->getMenace();
		}
	}
}

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

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

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

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

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

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

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

// Actualiza el campo de juego
void Game::updatePlayField()
{
	// Comprueba el teclado/mando
	checkGameInput();

	// Actualiza las variables del jugador
	updatePlayer();

	// Actualiza el fondo
	updateBackground();

	// Mueve los globos
	updateBalloons();

	// Mueve las balas
	moveBullets();

	// Actualiza los items
	updateItems();

	// Actualiza el valor de mCurrentStage
	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
	if (!mGameCompleted)
	{
		updateMenace();
	}

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

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

// Actualiza el fondo
void Game::updateBackground()
{
	mClouds1a->move();
	mClouds1b->move();
	mClouds2a->move();
	mClouds2b->move();

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

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

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

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

	mSpriteGrass->setSpriteClip(256, 85 + (6 * (mCounter / 20 % 2)), GAME_WIDTH, 6);

	if (mEffect.shake)
	{
		mSpriteBackground->setPosX(((mEffect.shakeCounter % 2) * 2) - 1);
	}
	else
	{
		mSpriteBackground->setPosX(0);
	}
}

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

	// Dibuja el gradiente 2
	mSpriteGradient->setSpriteClip(mGradientRect[((int)gradientNumber + 1) % 4]);
	mSpriteGradient->render();

	// Dibuja el gradiente 1 con una opacidad cada vez menor
	mSpriteGradient->setSpriteClip(mGradientRect[(int)gradientNumber]);
	mTextureGameBG->setAlpha(alpha);
	mSpriteGradient->render();
	mTextureGameBG->setAlpha(255);

	mClouds1a->render();
	mClouds1b->render();
	mClouds2a->render();
	mClouds2b->render();

	mSpriteBackground->render();

	mSpriteGrass->render();
}

// Dibuja el campo de juego
void Game::renderPlayField()
{
	renderBackground();
	renderBalloons();
	renderBullets();
	renderMessages();
	renderItems();
	renderSmartSprites();
	renderScoreBoard();

	for (auto player:players)
	{
		player->render();
	}

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

	if ((mGameCompleted) && (mGameCompletedCounter >= 300))
	{
		renderDeathFade(mGameCompletedCounter - 300);
	}

	renderFlashEffect();
}

// Gestiona el nivel de amenaza
void Game::updateMenace()
{
	const float percent = mStage[mCurrentStage].currentPower / mStage[mCurrentStage].powerToComplete;
	const Uint8 difference = mStage[mCurrentStage].maxMenace - mStage[mCurrentStage].minMenace;

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

	// Si el nivel de amenza es inferior al umbral
	if (mMenaceCurrent < mMenaceThreshold)
	{
		// 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()
{
	mDemo.keys.left = 0;
	mDemo.keys.right = 0;
	mDemo.keys.noInput = 0;
	mDemo.keys.fire = 0;
	mDemo.keys.fireLeft = 0;
	mDemo.keys.fireRight = 0;

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

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

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

		if (mDemo.dataFile[mDemo.counter].fire == 1)
		{
			if (players[index]->canFire())
			{
				players[index]->setInput(INPUT_BUTTON_2);
				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 (mDemo.dataFile[mDemo.counter].fireLeft == 1)
		{
			if (players[index]->canFire())
			{
				players[index]->setInput(INPUT_BUTTON_1);
				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 (mDemo.dataFile[mDemo.counter].fireRight == 1)
		{
			if (players[index]->canFire())
			{
				players[index]->setInput(INPUT_BUTTON_3);
				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 (mInput->checkInput(INPUT_BUTTON_PAUSE, REPEAT_FALSE))
		{
			mSection.name = PROG_SECTION_TITLE;
		}

		// Incrementa el contador de la demo
		if (mDemo.counter < TOTAL_DEMO_DATA)
		{
			mDemo.counter++;
		}
		else
		{
			mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS};
		}
	}
	// Modo Demo no activo
	else
	{
		int i = 0;
		for (auto player:players)
		{
			if (player->isAlive())
			{
				// Input a la izquierda
				if (mInput->checkInput(INPUT_LEFT, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
				{
					player->setInput(INPUT_LEFT);
					mDemo.keys.left = 1;
				}
				else
				{
					// Input a la derecha
					if (mInput->checkInput(INPUT_RIGHT, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
					{
						player->setInput(INPUT_RIGHT);
						mDemo.keys.right = 1;
					}
					else
					{
						// Ninguno de los dos inputs anteriores
						player->setInput(INPUT_NULL);
						mDemo.keys.noInput = 1;
					}
				}
				// Comprueba el input de disparar al centro
				if (mInput->checkInput(INPUT_BUTTON_2, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
				{
					if (player->canFire())
					{
						player->setInput(INPUT_BUTTON_2);
						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(mSoundBullet);

						mDemo.keys.fire = 1;
					}
				}

				// Comprueba el input de disparar a la izquierda
				if (mInput->checkInput(INPUT_BUTTON_1, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
				{
					if (player->canFire())
					{
						player->setInput(INPUT_BUTTON_1);
						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(mSoundBullet);

						mDemo.keys.fireLeft = 1;
					}
				}

				// Comprueba el input de disparar a la derecha
				if (mInput->checkInput(INPUT_BUTTON_3, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
				{
					if (player->canFire())
					{
						player->setInput(INPUT_BUTTON_3);
						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(mSoundBullet);

						mDemo.keys.fireRight = 1;
					}
				}

				// Comprueba el input de pausa
				if (mInput->checkInput(INPUT_CANCEL, REPEAT_FALSE, mOptions->input[i].deviceType, mOptions->input[i].id))
				{
					mSection.subsection = GAME_SECTION_PAUSE;

					if (JA_GetMusicState() == JA_MUSIC_PLAYING)
					{
						JA_PauseMusic();
					}
				}

				if (mDemo.counter < TOTAL_DEMO_DATA)
				{
					if (mDemo.recording)
					{
						mDemo.dataFile[mDemo.counter] = mDemo.keys;
					}
					mDemo.counter++;
				}
				else if (mDemo.recording)
				{
					mSection.name = PROG_SECTION_QUIT;
				}

				i++;
			}
		}
	}
}

// Pinta diferentes mensajes en la pantalla
void Game::renderMessages()
{
	// GetReady
	if ((mCounter < STAGE_COUNTER) && (!mDemo.enabled))
	{
		mSpriteGetReady->setPosX((int)mGetReadyBitmapPath[mCounter]);
		mTextNokiaBig2->write((int)mGetReadyBitmapPath[mCounter], PLAY_AREA_CENTER_Y - 8, mLang->getText(75), -2);
	}

	// Time Stopped
	if (mTimeStopped)
	{
		if ((mTimeStoppedCounter > 100) || (mTimeStoppedCounter % 10 > 4))
		{
			mTextNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, mLang->getText(36) + std::to_string(mTimeStoppedCounter / 10), -1, noColor, 1, shdwTxtColor);
		}

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

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

	// STAGE NUMBER
	if (mStageBitmapCounter < STAGE_COUNTER)
	{
		const int stage = mStage[mCurrentStage].number;
		std::string text;

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

		if (!mGameCompleted)
		{ // Escribe el numero de fases restantes
			mTextNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, mStageBitmapPath[mStageBitmapCounter], text, -2, noColor, 2, shdwTxtColor);
		}
		else
		{ // Escribe el texto de juego completado
			text = mLang->getText(50);
			mTextNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, mStageBitmapPath[mStageBitmapCounter], text, -2, noColor, 1, shdwTxtColor);
			mTextNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, mStageBitmapPath[mStageBitmapCounter] + mTextNokiaBig2->getCharacterSize() + 2, mLang->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()
{
	mTimeStopped = 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
		mScreen->start();

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

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

		mSpriteBackground->setPosX(255);
		mSpriteBackground->setSpriteClip(255, 0, 1, 192);
		mSpriteBackground->render();

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

		mSpriteGrass->render();
		renderBalloons();
		renderBullets();
		renderItems();
		for (auto player:players)
		{
			player->render();
		}
		renderScoreBoard();

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

// Bucle para el juego
section_t Game::run()
{
	init();

	while (mSection.name == PROG_SECTION_GAME)
	{
		// Sección juego en pausa
		if (mSection.subsection == GAME_SECTION_PAUSE)
		{
			runPausedGame();
		}

		// Sección Game Over
		if (mSection.subsection == GAME_SECTION_GAMEOVER)
		{
			runGameOverScreen();
		}

		// Sección juego jugando
		if ((mSection.subsection == GAME_SECTION_PLAY_1P) || (mSection.subsection == GAME_SECTION_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 (!mGameCompleted)
				{
					if (players[0]->isAlive())
					{
						JA_PlayMusic(mMusicPlaying);
					}
				}
			}

			// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
			if (SDL_GetTicks() - mTicks > mTicksSpeed)
			{
				// Actualiza el contador de ticks
				mTicks = SDL_GetTicks();

				// Actualiza el contador de juego
				mCounter++;

				// Comprueba los eventos que hay en la cola
				while (SDL_PollEvent(mEventHandler) != 0)
				{
					// Evento de salida de la aplicación
					if (mEventHandler->type == SDL_QUIT)
					{
						mSection.name = PROG_SECTION_QUIT;
						break;
					}
				}

				// Actualiza la lógica del juego
				updatePlayField();
			}

			// Prepara para empezar a dibujar en la textura de juego
			mScreen->start();

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

			// Dibuja los objetos
			renderPlayField();

			// Pinta la informacion de debug
			renderDebugInfo();

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

	return mSection;
}

// Bucle para el menu de pausa del juego
void Game::runPausedGame()
{
	// Reinicia el menu
	mMenuPause->reset();

	while ((mSection.subsection == GAME_SECTION_PAUSE) && (mSection.name == PROG_SECTION_GAME))
	{
		// Comprueba los eventos que hay en la cola
		while (SDL_PollEvent(mEventHandler) != 0)
		{
			// Evento de salida de la aplicación
			if (mEventHandler->type == SDL_QUIT)
			{
				mSection.name = PROG_SECTION_QUIT;
				break;
			}
		}

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

			// Actualiza la lógica del menu
			mMenuPause->update();
			mFade->update();
			if (mFade->hasEnded())
			{
				mSection.name = PROG_SECTION_TITLE;
				mSection.subsection = TITLE_SECTION_1;
				JA_StopMusic();
				break;
			}
		}

		// Prepara para empezar a dibujar en la textura de juego
		mScreen->start();

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

		// Pinta el escenario
		renderPlayField();
		mMenuPause->render();
		mFade->render();

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

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

		// Comprueba si se ha seleccionado algún item del menú
		switch (mMenuPause->getItemSelected())
		{
		case 0:
			mSection.name = PROG_SECTION_GAME;

			if (mNumPlayers == 1)
			{
				mSection.subsection = GAME_SECTION_PLAY_1P;
			}
			else
			{
				mSection.subsection = GAME_SECTION_PLAY_2P;
			}

			if (JA_GetMusicState() == JA_MUSIC_PAUSED)
			{
				JA_ResumeMusic();
			}
			break;

		case 1:
			mFade->setFadeType(FADE_CENTER);
			mFade->activateFade();
			break;

		default:
			break;
		}
	}
}

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

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

	while ((mSection.subsection == GAME_SECTION_GAMEOVER) && (mSection.name == PROG_SECTION_GAME))
	{
		// Comprueba los eventos que hay en la cola
		while (SDL_PollEvent(mEventHandler) != 0)
		{
			// Evento de salida de la aplicación
			if (mEventHandler->type == SDL_QUIT)
			{
				mSection.name = PROG_SECTION_QUIT;
				break;
			}
		}

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

			// Actualiza la lógica del menu
			mMenuGameOver->update();
			mFade->update();
			if (mFade->hasEnded())
			{
				switch (mPostFade)
				{
				case 0: // YES
					mSection.name = PROG_SECTION_GAME;

					if (mNumPlayers == 1)
					{
						mSection.subsection = GAME_SECTION_PLAY_1P;
					}
					else
					{
						mSection.subsection = GAME_SECTION_PLAY_2P;
					}

					init();
					break;

				case 1: // NO
					mSection.name = PROG_SECTION_TITLE;
					mSection.subsection = TITLE_SECTION_1;
					break;

				default:
					break;
				}

				break;
			}
		}

		// Prepara para empezar a dibujar en la textura de juego
		mScreen->start();

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

		// Dibuja los objetos
		if (mNumPlayers == 1)
		{
			mTextBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 4), mLang->getText(43));
			mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 1), mLang->getText(44) + std::to_string(players[0]->getScore()));
		}
		else
		{
			mTextBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - 36, mLang->getText(43));
			mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - 12, mLang->getText(77) + std::to_string(players[0]->getScore()));
			mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y, mLang->getText(78) + std::to_string(players[1]->getScore()));
		}
		mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y + BLOCK * 2, mLang->getText(45));
		mMenuGameOver->render();
		mFade->render();

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

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

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

		case 1: // NO
			mPostFade = 1;
			mFade->activateFade();
			break;

		default:
			break;
		}
	}
}

// Dibuja la informacion de debug en pantalla
void Game::renderDebugInfo()
{
	const color_t color = {0xFF, 0x20, 0x20};

	if (mDebug.enabled)
	{
		mText->writeShadowed(2, 2 + 0 * BLOCK, "menace(umb):  " + std::to_string(mMenaceCurrent) + "(" + std::to_string(mMenaceThreshold) + ")", color);
		mText->writeShadowed(2, 2 + 1 * BLOCK, "currentPower: " + std::to_string(mStage[mCurrentStage].currentPower), color);
		mText->writeShadowed(2, 2 + 2 * BLOCK, "mCurrentStage:" + std::to_string(mCurrentStage), color);
		mText->writeShadowed(2, 2 + 3 * BLOCK, "mCounter:     " + std::to_string(mCounter), color);
		mText->writeShadowed(2, 2 + 4 * BLOCK, "(R)enemyset:  " + std::to_string(mDebug.enemySet), color);
		mText->writeShadowed(2, 2 + 5 * BLOCK, "RGB:          " + std::to_string(mDebug.gradR) + "," + std::to_string(mDebug.gradG) + "," + std::to_string(mDebug.gradB), color);
		mText->writeShadowed(2, 2 + 6 * BLOCK, "(I)invuln:    " + std::to_string(players[0]->getInvulnerableCounter()), color);
		mText->writeShadowed(2, 2 + 7 * BLOCK, "balloons:     " + std::to_string(countBalloons()), color);
		mText->writeShadowed(2, 2 + 8 * BLOCK, "balloonsPop:  " + std::to_string(mBalloonsPopped), color);
		mText->writeShadowed(2, 2 + 9 * BLOCK, "(Z-X)ballSped:" + std::to_string(mEnemySpeed), color);
		mText->writeShadowed(2, 2 + 10 * BLOCK, "EGcounter:    " + std::to_string(mGameCompletedCounter), color);
	}
}

// Indica si se puede crear una powerball
bool Game::canPowerBallBeCreated()
{
	if ((!mPowerBallEnabled) && (calculateScreenPower() > POWERBALL_SCREENPOWER_MINIMUM) && (mPowerBallCounter == 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()
{
	// 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)
		{
			mStageBitmapPath[i] = (mSin[(int)((i * 1.8f) + 90)] * (distance) + centerPoint);
		}

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

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

	// Letrero de GetReady
	const int size = mTextNokiaBig2->lenght(mLang->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)
		{
			mGetReadyBitmapPath[i] = mSin[(int)(i * 1.8f)];
			mGetReadyBitmapPath[i] *= distance1;
			mGetReadyBitmapPath[i] -= size;
		}
		else if (i < secondPart)
		{
			mGetReadyBitmapPath[i] = (int)finish1;
		}
		else
		{
			mGetReadyBitmapPath[i] = mSin[(int)((i - 150) * 1.8f)];
			mGetReadyBitmapPath[i] *= distance2;
			mGetReadyBitmapPath[i] += finish1;
		}
	}
}

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

	if (mGameCompletedCounter == 500)
	{
		mSection.subsection = GAME_SECTION_GAMEOVER;
	}
}

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

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

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

	return success;
}