/*

Volcano (abans "Rise of the Bal1")
Programat i dissenyat per
	Sergio Valor @JailDesigner
Editor, música i suport técnic per
	Raimon Zamora @JailDoc
Gràfics per
	Diego Valor @JailBrother
Començat un 19 de febrer de 2016
Repres un 14 de febrer de 2021

*/

#include "volcano.h"
#include <iostream>

#define CLOSE_SOUND(a)     \
	if (a != nullptr)      \
		JA_DeleteSound(a); \
	a = nullptr
#define CLOSE_MUSIC(a)     \
	if (a != nullptr)      \
		JA_DeleteMusic(a); \
	a = nullptr

// DEBUG VARS
Uint8 _GRAVITY = 1;
Uint8 starting_rooms_to_test[4] = {3, 26, 100, 190};
Uint8 starting_room = 0;
// END DEBUG VARS

// FILES
std::string FILE_MAP_VOLCANO;
std::string FILE_TILES_VOLCANO;
std::string FILE_TILES_SURFACE;
std::string FILE_BKG_SURFACE;
std::string FILE_MENU;
std::string FILE_MENU_ANIMATION;
std::string FILE_ACTORS;
std::string FILE_PLAYER;
std::string FILE_HUD;
std::string FILE_FILTER;
std::string FILE_SOUND_JUMP;
std::string FILE_SOUND_DEATH;
std::string FILE_SOUND_COIN;
std::string FILE_SOUND_MENU_LOGO;
std::string FILE_SOUND_MENU_START;
std::string FILE_SOUND_DROP_ENEMY;
std::string FILE_SOUND_DROP_SPLAT;
std::string FILE_MUSIC_SURFACE;
std::string FILE_MUSIC_VOLCANO;
std::string FILE_MUSIC_MENU;
// END FILES

void allocatePointers()
{
	// Textures
	hud.sprite = new LTexture();
	map.background = new LTexture();
	map.sprite_actor = new LTexture();
	map.sprite_tile = new LTexture();
	menu.sprite = new LTexture();
	menu.sprite_animation = new LTexture();
	player.sprite = new LTexture();
	prog.sprite = new LTexture();
}

void deletePointers()
{
	// Textures
	delete hud.sprite;
	delete map.background;
	delete map.sprite_actor;
	delete map.sprite_tile;
	delete menu.sprite;
	delete menu.sprite_animation;
	delete player.sprite;
	delete prog.sprite;

	// Sounds
	CLOSE_SOUND(game.sound_drop_enemy);
	CLOSE_SOUND(game.sound_drop_splat);
	CLOSE_SOUND(menu.sound_logo);
	CLOSE_SOUND(menu.sound_start);
	CLOSE_SOUND(player.sound_coin);
	CLOSE_SOUND(player.sound_death);
	CLOSE_SOUND(player.sound_jump);

	delete[] map.tile;
	delete[] map.actor;
}

// Carga un archivo de imagen en una textura
bool loadTextureFromFile(LTexture *texture, std::string path, SDL_Renderer *renderer)
{
	bool success = true;
	if (!texture->loadFromFile(path, renderer))
	{
		printf("Failed to load %s texture!\n", path.c_str());
		success = false;
	}
	return success;
}

void ClosePicture(LTexture *picture)
{
	picture->free();
}

// Obtiene el valor del tile de la habitación actual
Uint8 GetTile(Uint8 x, Uint8 y)
{
	long room_x = (map.room % 12) * ROOM_WIDTH_IN_TILES;
	long room_y = (map.room / 12) * ROOM_HEIGHT_IN_TILES;
	return map.tile[(room_x + x) + (room_y + y) * map.w];
}

Uint8 ReadMapTile(Uint8 x, Uint8 y)
{
	if (GetTile(x, y) >= 0 && GetTile(x, y) <= 63)
		return TILE_BACKGROUND;
	else if (GetTile(x, y) >= 64 && GetTile(x, y) <= 143)
		return TILE_PLATFORM;
	else if (GetTile(x, y) >= 144 && GetTile(x, y) <= 175)
		return TILE_TRAVESABLE_PLATFORM;
	else if (GetTile(x, y) >= 176 && GetTile(x, y) <= 207)
		return TILE_KILLING_PLATFORM;
	else if (GetTile(x, y) >= 208 && GetTile(x, y) <= 255)
		return TILE_ACTOR;
	else
		return 0;
}

Uint8 GetActor(Uint8 x, Uint8 y)
{
	long room_x = (map.room % 12) * ROOM_WIDTH_IN_TILES;
	long room_y = (map.room / 12) * ROOM_HEIGHT_IN_TILES;
	return map.actor[(room_x + x) + (room_y + y) * map.w];
}

void SetActor(Uint8 x, Uint8 y, Uint8 valor)
{
	long room_x = (map.room % 12) * ROOM_WIDTH_IN_TILES;
	long room_y = (map.room / 12) * ROOM_HEIGHT_IN_TILES;
	map.actor[(room_x + x) + (room_y + y) * map.w] = valor;
}

void SetMapGFX(Uint8 zone)
{
	switch (zone)
	{
	case ZONE_SURFACE:
		loadTextureFromFile(map.sprite_tile, FILE_TILES_SURFACE.c_str(), renderer);
		loadTextureFromFile(map.background, FILE_BKG_SURFACE.c_str(), renderer);
		break;

	case ZONE_VOLCANO:
		loadTextureFromFile(map.sprite_tile, FILE_TILES_VOLCANO.c_str(), renderer);
		loadTextureFromFile(map.background, FILE_BKG_SURFACE.c_str(), renderer);
		break;
	}
}

void SetMapMusic(Uint8 zone)
{
	switch (zone)
	{
	case ZONE_SURFACE:
		game.music = JA_LoadMusic(FILE_MUSIC_SURFACE.c_str());
		break;

	case ZONE_VOLCANO:
		game.music = JA_LoadMusic(FILE_MUSIC_VOLCANO.c_str());
		break;
	}
}

bool CheckZoneChange(int room)
{
	Uint8 zone = 0;

	if ((room >= 0) && (room <= 23))
		zone = ZONE_SURFACE;
	else if ((room >= 24) && (room <= 255))
		zone = ZONE_VOLCANO;

	if (zone == game.zone)
		return false;
	else
		return true;
}

void SetZone(int room)
{
	if ((room >= 0) && (room <= 23))
		game.zone = ZONE_SURFACE;
	else if ((room >= 24) && (room <= 255))
		game.zone = ZONE_VOLCANO;

	SetMapGFX(game.zone);
	SetMapMusic(game.zone);
	JA_PlayMusic(game.music, -1);
}

void SetPlayerAnimation(Uint8 anim)
{
	if (anim != player.active_animation)
	{
		player.active_animation = anim;
		player.src_rect.y = anim * player.src_rect.h;
		player.animation[anim].index = 0;
		player.animation[anim].timer = 0;
		player.animation[anim].loops = false;
	}
}

void Animate(Tanimation &a, SDL_Rect &s)
{
	// Mirem si estem en el penultim frame per avisar de que anem a pintar el ultim
	if (a.timer == (a.num_frames * a.speed) - 2)
		a.loops = true;
	else
		a.loops = false;

	a.timer = (a.timer + 1) % (a.num_frames * a.speed);
	a.index = a.timer / a.speed;
	s.x = (a.frame[a.index]) * s.w;
}

void AnimateIntroMenu(Tanimation &a, SDL_Rect &s)
{
	// Mirem si estem en el penultim frame per avisar de que anem a pintar el ultim
	if (a.timer == ((a.num_frames) * (a.speed)) - 2)
		a.loops = true;
	else
		a.loops = false;

	a.timer = (a.timer + 1) % (a.num_frames * a.speed);
	a.index = a.timer / a.speed;
	s.x = (a.frame[a.index] % 4) * s.w;
	s.y = (a.frame[a.index] / 4) * s.h;
}

void CreateActor(Tactor &a, Uint8 kind, Uint8 id, Sint16 dstx, Sint16 dsty, Sint16 dstw, Sint16 dsth, Sint16 srcx, Sint16 srcy, Sint16 sx,
				 Sint16 sy, Sint16 timer, Sint16 frame, Uint8 direction, Uint8 parent)
{
	a.kind = kind;
	a.id = id;
	a.dst_rect.x = dstx;
	a.dst_rect.y = dsty;
	a.dst_rect.w = dstw;
	a.dst_rect.h = dsth;
	a.src_rect.x = srcx;
	a.src_rect.y = srcy;
	a.src_rect.w = a.dst_rect.w;
	a.src_rect.h = a.dst_rect.h;
	a.direction = direction;
	a.speed_x = sx;
	a.speed_y = sy;
	a.timer = timer;
	a.frame = frame;
	a.enabled = true;
	a.parent = parent;
}

void setExecutablePath(std::string path)
{
	executablePath = path.substr(0, path.find_last_of("\\/"));
	//printf("path: %s\n", executablePath.c_str());
	
	std::string p;
	SDL_RWops *file;

	p = FILE_MAP_VOLCANO = executablePath + "/../data/volcano.map.bak1";
//	printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_TILES_VOLCANO = executablePath + "/../media/gfx/tiles_volcano.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_TILES_SURFACE = executablePath + "/../media/gfx/tiles_surface.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_BKG_SURFACE = executablePath + "/../media/gfx/bkg_surface.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_MENU = executablePath + "/../media/gfx/menu.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_MENU_ANIMATION = executablePath + "/../media/gfx/menu_animation.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_ACTORS = executablePath + "/../media/gfx/actors.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_PLAYER = executablePath + "/../media/gfx/player.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_HUD = executablePath + "/../media/gfx/hud.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_FILTER = executablePath + "/../media/gfx/filter.png";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_JUMP = executablePath + "/../media/sound/sound_player_jump.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_DEATH = executablePath + "/../media/sound/sound_player_death.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_COIN = executablePath + "/../media/sound/sound_player_coin.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_MENU_LOGO = executablePath + "/../media/sound/sound_menu_logo.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_MENU_START = executablePath + "/../media/sound/sound_menu_start.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_DROP_ENEMY = executablePath + "/../media/sound/sound_drop_enemy.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_SOUND_DROP_SPLAT = executablePath + "/../media/sound/sound_drop_splat.wav";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_MUSIC_SURFACE = executablePath + "/../media/music/music_surface.ogg";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_MUSIC_VOLCANO = executablePath + "/../media/music/music_volcano.ogg";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);

	p = FILE_MUSIC_MENU = executablePath + "/../media/music/music_menu.ogg";
	//printf("%s\n",p.c_str());
	file = SDL_RWFromFile(p.c_str(), "r+b");
	if (file != NULL)
	{
		//printf("Checking file %-20s [OK]\n", p.c_str());
	}
	SDL_RWclose(file);
}

void LoadMap()
{
	std::string p = FILE_MAP_VOLCANO.c_str();
	std::string filename = p.substr(p.find_last_of("\\/") + 1);

	SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b");

	if (file == NULL)
	{
		printf("Warning: Unable to open %s file\n", filename.c_str());
	}
	else
	{
		printf("Reading file %s\n", filename.c_str());

		SDL_RWread(file, &map.w, sizeof(Uint8), 1);
		SDL_RWread(file, &map.h, sizeof(Uint8), 1);

		long size = (map.w) * (map.h);

		map.tile = new Uint8[size];
		map.actor = new Uint8[size];

		for (Uint32 i = 0; i < size; i++)
			SDL_RWread(file, &map.tile[i], sizeof(Uint8), 1);

		for (Uint32 i = 0; i < size; i++)
			SDL_RWread(file, &map.actor[i], sizeof(Uint8), 1);

		SDL_RWclose(file);
	}
}

void LoadRoom(int num)
{
	if (CheckZoneChange(num))
		SetZone(num);

	// Coloquem el numero d'habitaci� corresponent al mapa
	map.room = std::max(0, num);

	// Guardem les coordenades i el sentit que te el jugador al entrar a la habitaci�
	player.respawn_x = player.dst_rect.x;
	player.respawn_y = player.dst_rect.y;
	player.respawn_direction = player.direction;

	// Esborrem la llista de tiles animats
	for (Uint8 i = 0; i < MAX_ANIMATED_TILES; i++)
		animated_tile[i].enabled = false;

	// Escanejem la habitaci en busca de tiles animats
	Uint8 k = 0;
	for (Uint8 i = 0; i < ROOM_WIDTH_IN_TILES; i++)
		for (Uint8 j = 0; j < ROOM_HEIGHT_IN_TILES; j++)
			if (((GetTile(i, j) >= 48) && (GetTile(i, j) <= 63)) ||
				((GetTile(i, j) >= 128) && (GetTile(i, j) <= 143)) ||
				((GetTile(i, j) >= 160) && (GetTile(i, j) <= 175)) ||
				((GetTile(i, j) >= 192) && (GetTile(i, j) <= 207)))
			{
				animated_tile[k].enabled = true;
				animated_tile[k].x = i * MAP_TILE_WIDTH;
				animated_tile[k].y = j * MAP_TILE_HEIGHT;
				animated_tile[k].index = GetTile(i, j);
				animated_tile[k].frame = 0;
				k++;
			}

	// Esborrem la llista d'actors actius
	for (Uint8 i = 0; i < MAX_ACTORS; i++)
		actor[i].enabled = false;

	// Escanejem la habitaci� en busca d'actors per afegirlos a la llista d'actors actius
	k = 0;
	for (Uint8 i = 0; i < ROOM_WIDTH_IN_TILES; i++)
		for (Uint8 j = 0; j < ROOM_HEIGHT_IN_TILES; j++)
		{
			switch (GetActor(i, j))
			{
			case CODE_ENEMY_V1U:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 0, 1, 0, 0, UP, k);
				break;

			case CODE_ENEMY_V2U:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 0, 2, 0, 0, UP, k);
				break;

			case CODE_ENEMY_V3U:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 0, 3, 0, 0, UP, k);
				break;

			case CODE_ENEMY_V1D:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 0, 1, 0, 0, DOWN, k);
				break;

			case CODE_ENEMY_V2D:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 0, 2, 0, 0, DOWN, k);
				break;

			case CODE_ENEMY_V3D:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 0, 3, 0, 0, DOWN, k);
				break;

			case CODE_ENEMY_H1L:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 1, 0, 0, 0, LEFT, k);
				break;

			case CODE_ENEMY_H2L:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 2, 0, 0, 0, LEFT, k);
				break;

			case CODE_ENEMY_H3L:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 3, 0, 0, 0, LEFT, k);
				break;

			case CODE_ENEMY_H1R:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 1, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_H2R:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 2, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_H3R:
				CreateActor(actor[k], KIND_FLYING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 4 * 16, 3, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_W1L:
				CreateActor(actor[k], KIND_WALKING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 1 * 16, 1, 0, 0, 0, LEFT, k);
				break;

			case CODE_ENEMY_W2L:
				CreateActor(actor[k], KIND_WALKING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 1 * 16, 2, 0, 0, 0, LEFT, k);
				break;

			case CODE_ENEMY_W3L:
				CreateActor(actor[k], KIND_WALKING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 1 * 16, 3, 0, 0, 0, LEFT, k);
				break;

			case CODE_ENEMY_W1R:
				CreateActor(actor[k], KIND_WALKING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 0 * 16, 1, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_W2R:
				CreateActor(actor[k], KIND_WALKING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 0 * 16, 2, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_W3R:
				CreateActor(actor[k], KIND_WALKING_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 0 * 16, 3, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_SPL:
				CreateActor(actor[k], KIND_SPEED_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 3 * 16, 1, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_SPR:
				CreateActor(actor[k], KIND_SPEED_ENEMY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 2 * 16, 1, 0, 0, 0, RIGHT, k);
				break;

			case CODE_ENEMY_DRP:
				CreateActor(actor[k], KIND_DROP_GENERATOR, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 10 * 16, 0, 0, DROP_TIMER, 0, NONE, k);
				break;

			case CODE_COIN:
				CreateActor(actor[k], KIND_COIN, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 12 * 16, 0, 0, 0, 0, NONE, k);
				break;

			case CODE_HEART:
				CreateActor(actor[k], KIND_HEART, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 13 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_KEY_RED:
				CreateActor(actor[k], KIND_KEY, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 14 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_LOCK_RED:
				CreateActor(actor[k], KIND_LOCK, 0, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 0, 15 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_KEY_BLUE:
				CreateActor(actor[k], KIND_KEY, 1, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 1 * 16, 14 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_LOCK_BLUE:
				CreateActor(actor[k], KIND_LOCK, 1, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 1 * 16, 15 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_KEY_GREEN:
				CreateActor(actor[k], KIND_KEY, 2, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 2 * 16, 14 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_LOCK_GREEN:
				CreateActor(actor[k], KIND_LOCK, 2, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 2 * 16, 15 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_KEY_YELLOW:
				CreateActor(actor[k], KIND_KEY, 3, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 3 * 16, 14 * 16, 1, 0, 0, 0, NONE, k);
				break;

			case CODE_LOCK_YELLOW:
				CreateActor(actor[k], KIND_LOCK, 3, i * MAP_TILE_WIDTH, j * MAP_TILE_HEIGHT, 16, 16, 3 * 16, 15 * 16, 1, 0, 0, 0, NONE, k);
				break;

			default:
				k--;
				break;
			}
			k++;
		}
}

void IniMenu()
{

	menu.enabled = true;
	menu.section = MENU_SECTION_ANIMATION;

	menu.music = JA_LoadMusic(FILE_MUSIC_MENU.c_str());
	menu.sound_logo = JA_LoadSound(FILE_SOUND_MENU_LOGO.c_str());
	menu.sound_start = JA_LoadSound(FILE_SOUND_MENU_START.c_str());

	loadTextureFromFile(menu.sprite, FILE_MENU.c_str(), renderer);
	menu.frame = 0;
	menu.timer = 200;

	// Fondo
	menu.src_rect_fondo.x = 0;
	menu.src_rect_fondo.y = 0;
	menu.src_rect_fondo.w = 320;
	menu.src_rect_fondo.h = 240;

	menu.dst_rect_fondo.x = 0;
	menu.dst_rect_fondo.y = 0;
	menu.dst_rect_fondo.w = 320;
	menu.dst_rect_fondo.h = 240;

	// Logo
	menu.src_rect_logo.x = 0;
	menu.src_rect_logo.y = 240;
	menu.src_rect_logo.w = 260;
	menu.src_rect_logo.h = 154;

	menu.dst_rect_logo.x = 30;
	menu.dst_rect_logo.y = 30;
	menu.dst_rect_logo.w = 260;
	menu.dst_rect_logo.h = 154;

	menu.dst_rect_logo_zoom.x = 0;
	menu.dst_rect_logo_zoom.y = 0;
	menu.dst_rect_logo_zoom.w = 0;
	menu.dst_rect_logo_zoom.h = 0;

	// PRESS RETURN TO START
	menu.src_rect_text.x = 0;
	menu.src_rect_text.y = 394;
	menu.src_rect_text.w = 125;
	menu.src_rect_text.h = 7;

	menu.dst_rect_text.x = (320 - 125) / 2;
	menu.dst_rect_text.y = 195;
	menu.dst_rect_text.w = 125;
	menu.dst_rect_text.h = 7;

	// JAILGAMES 2016
	menu.src_rect_text2.x = 0;
	menu.src_rect_text2.y = 394 + 7;
	menu.src_rect_text2.w = 55;
	menu.src_rect_text2.h = 5;

	menu.dst_rect_text2.x = (320 - 55) / 2;
	menu.dst_rect_text2.y = 210;
	menu.dst_rect_text2.w = 55;
	menu.dst_rect_text2.h = 5;

	// Animación
	loadTextureFromFile(menu.sprite_animation, FILE_MENU_ANIMATION.c_str(), renderer);

	menu.src_rect_animation.x = 0;
	menu.src_rect_animation.y = 0;
	menu.src_rect_animation.w = 320;
	menu.src_rect_animation.h = 240;

	menu.dst_rect_animation.x = 0;
	menu.dst_rect_animation.y = 0;
	menu.dst_rect_animation.w = 320;
	menu.dst_rect_animation.h = 240;

	menu.animation[0].num_frames = 29;
	menu.animation[0].index = 0;
	menu.animation[0].timer = 0;
	menu.animation[0].speed = 9;
	menu.animation[0].loops = false;

	menu.animation[0].frame[0] = 0;
	menu.animation[0].frame[1] = 1;
	menu.animation[0].frame[2] = 0;
	menu.animation[0].frame[3] = 1;
	menu.animation[0].frame[4] = 2;
	menu.animation[0].frame[5] = 3;
	menu.animation[0].frame[6] = 4;
	menu.animation[0].frame[7] = 5;
	menu.animation[0].frame[8] = 6;
	menu.animation[0].frame[9] = 7;
	menu.animation[0].frame[10] = 8;
	menu.animation[0].frame[11] = 9;
	menu.animation[0].frame[12] = 10;
	menu.animation[0].frame[13] = 11;
	menu.animation[0].frame[14] = 12;
	menu.animation[0].frame[15] = 13;
	menu.animation[0].frame[16] = 14;
	menu.animation[0].frame[17] = 15;
	menu.animation[0].frame[18] = 16;
	menu.animation[0].frame[19] = 17;
	menu.animation[0].frame[20] = 18;
	menu.animation[0].frame[21] = 19;
	menu.animation[0].frame[22] = 20;
	menu.animation[0].frame[23] = 21;
	menu.animation[0].frame[24] = 22;
	menu.animation[0].frame[25] = 23;
	menu.animation[0].frame[26] = 24;
	menu.animation[0].frame[27] = 25;
	menu.animation[0].frame[28] = 26;

	menu.animation[1].num_frames = 23;
	menu.animation[1].index = 0;
	menu.animation[1].timer = 0;
	menu.animation[1].speed = 9;
	menu.animation[1].loops = false;

	menu.animation[1].frame[0] = 18;
	menu.animation[1].frame[1] = 26;
	menu.animation[1].frame[2] = 18;
	menu.animation[1].frame[3] = 26;
	menu.animation[1].frame[4] = 18;
	menu.animation[1].frame[5] = 26;
	menu.animation[1].frame[6] = 18;
	menu.animation[1].frame[7] = 26;
	menu.animation[1].frame[8] = 18;
	menu.animation[1].frame[9] = 26;
	menu.animation[1].frame[10] = 18;
	menu.animation[1].frame[11] = 26;
	menu.animation[1].frame[12] = 18;
	menu.animation[1].frame[13] = 26;
	menu.animation[1].frame[14] = 18;
	menu.animation[1].frame[15] = 19;
	menu.animation[1].frame[16] = 20;
	menu.animation[1].frame[17] = 21;
	menu.animation[1].frame[18] = 22;
	menu.animation[1].frame[19] = 23;
	menu.animation[1].frame[20] = 24;
	menu.animation[1].frame[21] = 25;
	menu.animation[1].frame[22] = 26;
}

void EndMenu()
{

	CLOSE_SOUND(menu.sound_logo);
	CLOSE_SOUND(menu.sound_start);
	CLOSE_MUSIC(menu.music);
	ClosePicture(menu.sprite);
	ClosePicture(menu.sprite_animation);
	menu.enabled = false;
}

void IniActors()
{
	for (Uint8 i = 0; i < MAX_ACTORS; i++)
		actor[i].enabled = false;
	loadTextureFromFile(map.sprite_actor, FILE_ACTORS.c_str(), renderer);
}

void IniAnimatedTiles()
{
	for (Uint8 i = 0; i < MAX_ANIMATED_TILES; i++)
		animated_tile[i].enabled = false;
}

void IniMap()
{

	map.src_rect.x = 0;
	map.src_rect.y = 0;
	map.src_rect.w = 320;
	map.src_rect.h = 240;

	map.dst_rect.x = 0;
	map.dst_rect.y = 0;
	map.dst_rect.w = 320;
	map.dst_rect.h = 240;

	LoadMap();
}

void EndMap()
{
	ClosePicture(map.sprite_tile);
	ClosePicture(map.sprite_actor);
	ClosePicture(map.background);
}

void IniPlayer()
{
	loadTextureFromFile(player.sprite, FILE_PLAYER.c_str(), renderer);
	player.dst_rect.x = MAP_TILE_WIDTH * STARTING_PLAYER_TILE_X;
	player.dst_rect.y = MAP_TILE_HEIGHT * STARTING_PLAYER_TILE_Y;
	player.dst_rect.w = 16;
	player.dst_rect.h = 24;
	player.src_rect.x = 0;
	player.src_rect.y = 0;
	player.src_rect.w = player.dst_rect.w;
	player.src_rect.h = player.dst_rect.h;
	player.direction = RIGHT;
	player.respawn_x = player.dst_rect.x;
	player.respawn_y = player.dst_rect.y;
	player.respawn_direction = player.direction;
	player.speed_x = BASE_SPEED;
	player.speed_y = 0;
	player.can_jump = true;
	player.jump_pressed_now = false;
	player.jump_pressed_before = false;
	player.standing = true;
	player.invulnerable = false;
	player.jumpforce = 10;
	player.active_animation = 0;
	player.enabled = true;
	player.cooldown = 0;
	player.lifes = 10;
	player.coins = 0;
	for (Uint8 i = 0; i < 6; i++)
		player.key[i] = false;
	player.sound_jump = JA_LoadSound(FILE_SOUND_JUMP.c_str());
	player.sound_death = JA_LoadSound(FILE_SOUND_DEATH.c_str());
	player.sound_coin = JA_LoadSound(FILE_SOUND_COIN.c_str());

	player.animation[0].num_frames = 33;
	player.animation[0].index = 0;
	player.animation[0].timer = 0;
	player.animation[0].speed = 6;
	player.animation[0].loops = false;
	player.animation[0].frame[0] = 0;
	player.animation[0].frame[1] = 1;
	player.animation[0].frame[2] = 2;
	player.animation[0].frame[3] = 2;
	player.animation[0].frame[4] = 1;
	player.animation[0].frame[5] = 0;
	player.animation[0].frame[6] = 0;
	player.animation[0].frame[7] = 1;
	player.animation[0].frame[8] = 2;
	player.animation[0].frame[9] = 2;
	player.animation[0].frame[10] = 1;
	player.animation[0].frame[11] = 0;
	player.animation[0].frame[12] = 0;
	player.animation[0].frame[13] = 1;
	player.animation[0].frame[14] = 2;
	player.animation[0].frame[15] = 2;
	player.animation[0].frame[16] = 1;
	player.animation[0].frame[17] = 0;
	player.animation[0].frame[18] = 0;
	player.animation[0].frame[19] = 1;
	player.animation[0].frame[20] = 2;
	player.animation[0].frame[21] = 3;
	player.animation[0].frame[22] = 4;
	player.animation[0].frame[23] = 4;
	player.animation[0].frame[24] = 5;
	player.animation[0].frame[25] = 5;
	player.animation[0].frame[26] = 4;
	player.animation[0].frame[27] = 4;
	player.animation[0].frame[28] = 5;
	player.animation[0].frame[29] = 5;
	player.animation[0].frame[30] = 6;
	player.animation[0].frame[31] = 6;
	player.animation[0].frame[32] = 7;

	player.animation[1] = player.animation[0];

	player.animation[2].num_frames = 8;
	player.animation[2].index = 0;
	player.animation[2].speed = 4;
	player.animation[2].loops = false;
	player.animation[2].frame[0] = 0;
	player.animation[2].frame[1] = 1;
	player.animation[2].frame[2] = 2;
	player.animation[2].frame[3] = 3;
	player.animation[2].frame[4] = 4;
	player.animation[2].frame[5] = 5;
	player.animation[2].frame[6] = 6;
	player.animation[2].frame[7] = 7;

	player.animation[3] = player.animation[2];

	player.animation[4] = player.animation[2];

	player.animation[5] = player.animation[2];

	player.animation[6].num_frames = 20;
	player.animation[6].index = 0;
	player.animation[6].speed = 6;
	player.animation[6].loops = false;
	player.animation[6].frame[0] = 0;
	player.animation[6].frame[1] = 1;
	player.animation[6].frame[2] = 2;
	player.animation[6].frame[3] = 3;
	player.animation[6].frame[4] = 4;
	player.animation[6].frame[5] = 5;
	player.animation[6].frame[6] = 6;
	player.animation[6].frame[7] = 7;
	player.animation[6].frame[8] = 7;
	player.animation[6].frame[9] = 7;
	player.animation[6].frame[10] = 7;
	player.animation[6].frame[11] = 7;
	player.animation[6].frame[12] = 7;
	player.animation[6].frame[13] = 7;
	player.animation[6].frame[14] = 7;
	player.animation[6].frame[15] = 7;
	player.animation[6].frame[16] = 7;
	player.animation[6].frame[17] = 7;
	player.animation[6].frame[18] = 7;
	player.animation[6].frame[19] = 7;

	player.animation[7] = player.animation[6];
}

void EndPlayer()
{
	ClosePicture(player.sprite);
	CLOSE_SOUND(player.sound_jump);
	CLOSE_SOUND(player.sound_death);
	CLOSE_SOUND(player.sound_coin);
}

void IniHud()
{
	loadTextureFromFile(hud.sprite, FILE_HUD.c_str(), renderer);
	hud.src_rect.x = 0; // Origen de la textura para el marcador
	hud.src_rect.y = 0;
	hud.src_rect.w = 320;
	hud.src_rect.h = 16;

	hud.dst_rect.x = 0; // Donde se pinta el marcador
	hud.dst_rect.y = 224;
	hud.dst_rect.w = 320;
	hud.dst_rect.h = 16;

	hud.num_src_rect.x = 0; // Coordenada al primer numero pequeño
	hud.num_src_rect.y = 16;
	hud.num_src_rect.w = 5;
	hud.num_src_rect.h = 5;

	hud.num_dst_rect.x = 0; // Donde se pinta el numero pequeño
	hud.num_dst_rect.y = 16;
	hud.num_dst_rect.w = 5;
	hud.num_dst_rect.h = 5;

	hud.bignum_src_rect.x = 0; // Coordenada al primer numero grande
	hud.bignum_src_rect.y = 21;
	hud.bignum_src_rect.w = 7;
	hud.bignum_src_rect.h = 7;

	hud.bignum_dst_rect.x = 0; // Donde se pinta el numero grande
	hud.bignum_dst_rect.y = 21;
	hud.bignum_dst_rect.w = 7;
	hud.bignum_dst_rect.h = 7;
}

void EndHud()
{
	ClosePicture(hud.sprite);
}

void IniGame(Uint8 zone)
{
	game.sound_drop_enemy = JA_LoadSound(FILE_SOUND_DROP_ENEMY.c_str());
	game.sound_drop_splat = JA_LoadSound(FILE_SOUND_DROP_SPLAT.c_str());
	game.enabled = true;
	game.zone = zone;

	// Establir el color d'esborrat
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

	// Inicialitzar jugador
	IniPlayer();

	// Inicialitza mapa
	IniMap();
	SetMapGFX(zone);
	SetMapMusic(zone);

	// Inicialitza hud
	IniHud();

	// Inicialitza actors
	IniActors();

	// Inicialitza tiles animats
	IniAnimatedTiles();
}

void EndGame()
{
	EndPlayer();
	EndHud();
	EndMap();
	CLOSE_SOUND(game.sound_drop_enemy);
	CLOSE_SOUND(game.sound_drop_splat);
	if (JA_GetMusicState() == JA_MUSIC_PLAYING)
		JA_StopMusic();
	CLOSE_MUSIC(game.music);
	game.enabled = false;
}

void KillPlayer()
{
	if (!player.invulnerable)
	{
		player.enabled = false;
		player.cooldown = COOLDOWN_TIME;

		// Establece la animación de morir
		if (player.direction == LEFT)
			SetPlayerAnimation(PLAYER_ANIMATION_DYING_LEFT);
		else
			SetPlayerAnimation(PLAYER_ANIMATION_DYING_RIGHT);

		JA_PlaySound(player.sound_death, 0);
	}
}

bool OnFloor()
{
	Uint8 tile_under_left_foot = ReadMapTile((player.dst_rect.x + 3) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) / MAP_TILE_HEIGHT);
	Uint8 tile_under_right_foot = ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) / MAP_TILE_HEIGHT);

	bool i_am_above_platform = ((tile_under_left_foot == TILE_PLATFORM) || (tile_under_right_foot == TILE_PLATFORM));
	bool i_am_above_travesable = ((tile_under_left_foot == TILE_TRAVESABLE_PLATFORM) || (tile_under_right_foot == TILE_TRAVESABLE_PLATFORM));

	Uint8 tile_on_left_foot = ReadMapTile((player.dst_rect.x + 3) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT);
	Uint8 tile_on_right_foot = ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT);

	bool i_am_on_background = ((tile_on_left_foot == TILE_BACKGROUND) && (tile_on_right_foot == TILE_BACKGROUND));

	if (((i_am_above_platform) || (i_am_above_travesable)) && (i_am_on_background))
		return true;
	else
		return false;
}

void MoveActors()
{
	for (Uint8 i = 0; i < MAX_ACTORS; i++)
		if (actor[i].enabled)
			switch (actor[i].kind)
			{
			case KIND_FLYING_ENEMY:
				switch (actor[i].direction)
				{
				case RIGHT:
					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x + actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x + actor[i].dst_rect.w > GAME_WINDOW_WIDTH)
						actor[i].direction = LEFT;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) % MAP_TILE_WIDTH);
						actor[i].direction = LEFT;
					}
					break;

				case LEFT:
					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x - actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x < 0)
						actor[i].direction = RIGHT;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x % MAP_TILE_WIDTH));
						actor[i].direction = RIGHT;
					}
					break;

				case DOWN:
					// Calculem la nova posici�
					actor[i].dst_rect.y = actor[i].dst_rect.y + actor[i].speed_y;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.y + actor[i].dst_rect.h > GAME_WINDOW_HEIGHT)
						actor[i].direction = UP;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.y = actor[i].dst_rect.y - ((actor[i].dst_rect.y + actor[i].dst_rect.h) % MAP_TILE_WIDTH);
						actor[i].direction = UP;
					}
					break;

				case UP:
					// Calculem la nova posici�
					actor[i].dst_rect.y = actor[i].dst_rect.y - actor[i].speed_y;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.y < 0)
						actor[i].direction = DOWN;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.y = actor[i].dst_rect.y + (MAP_TILE_WIDTH - (actor[i].dst_rect.y % MAP_TILE_WIDTH));
						actor[i].direction = DOWN;
					}
					break;
				}

				actor[i].frame = (actor[i].frame + 1) % 24;
				if (actor[i].direction == UP)
					actor[i].src_rect.y = 4 * 16;
				if (actor[i].direction == DOWN)
					actor[i].src_rect.y = 5 * 16;
				if (actor[i].direction == LEFT)
					actor[i].src_rect.y = 7 * 16;
				if (actor[i].direction == RIGHT)
					actor[i].src_rect.y = 6 * 16;
				actor[i].src_rect.x = (actor[i].frame / 4) * actor[i].dst_rect.w;
				break;

			case KIND_WALKING_ENEMY:
				switch (actor[i].direction)
				{
				case RIGHT:
					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x + actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x + actor[i].dst_rect.w > GAME_WINDOW_WIDTH)
						actor[i].direction = LEFT;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) % MAP_TILE_WIDTH);
						actor[i].direction = LEFT;
					}

					// Arriba a la vora, correcci� a l'ultim pixel bo i canvi de sentit
					if (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 3) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) / MAP_TILE_HEIGHT) != TILE_PLATFORM)
						actor[i].direction = LEFT;
					break;

				case LEFT:
					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x - actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x < 0)
						actor[i].direction = RIGHT;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x % MAP_TILE_WIDTH));
						actor[i].direction = RIGHT;
					}

					// Arriba a la vora, correcci� a l'ultim pixel bo i canvi de sentit
					if (ReadMapTile((actor[i].dst_rect.x + 3) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) / MAP_TILE_HEIGHT) != TILE_PLATFORM)
						actor[i].direction = RIGHT;
					break;
				}

				// Animacio
				actor[i].frame = (actor[i].frame + 1) % 48;
				if (actor[i].direction == LEFT)
					actor[i].src_rect.y = 1 * 16;
				else
					actor[i].src_rect.y = 0 * 16;
				actor[i].src_rect.x = (actor[i].frame / 8) * actor[i].dst_rect.w;
				break;

			case KIND_SPEED_ENEMY:
				switch (actor[i].direction)
				{
				case RIGHT:
					// Mirem si estem en la mateixa altura que el jugador i fem que es meneje m�s r�pid
					if ((actor[i].dst_rect.y + 8 > player.dst_rect.y) && (actor[i].dst_rect.y + 8 < player.dst_rect.y + player.dst_rect.h - 1) && (player.can_jump))
						actor[i].speed_x = 3;
					else
						actor[i].speed_x = 1;

					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x + actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x + actor[i].dst_rect.w > GAME_WINDOW_WIDTH)
						actor[i].direction = LEFT;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) % MAP_TILE_WIDTH);
						actor[i].direction = LEFT;
					}

					// Arriba a la vora, correcci� a l'ultim pixel bo i canvi de sentit
					if (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 3) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) / MAP_TILE_HEIGHT) != TILE_PLATFORM)
						actor[i].direction = LEFT;
					break;

				case LEFT:
					// Mirem si estem en la mateixa altura que el jugador i fem que es meneje m�s r�pid
					if ((actor[i].dst_rect.y + 8 > player.dst_rect.y) && (actor[i].dst_rect.y + 8 < player.dst_rect.y + player.dst_rect.h - 1) && (player.can_jump))
						actor[i].speed_x = 3;
					else
						actor[i].speed_x = 1;

					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x - actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x < 0)
						actor[i].direction = RIGHT;

					// Colisi� amb el mapa, correcci� a l'ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x % MAP_TILE_WIDTH));
						actor[i].direction = RIGHT;
					}

					// Arriba a la vora, correcci� a l'ultim pixel bo i canvi de sentit
					if (ReadMapTile((actor[i].dst_rect.x + 3) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) / MAP_TILE_HEIGHT) != TILE_PLATFORM)
						actor[i].direction = RIGHT;
					break;
				}

				// Animacio
				actor[i].frame = (actor[i].frame + 1) % 48;
				if (actor[i].direction == LEFT)
					actor[i].src_rect.y = 2 * 16;
				else
					actor[i].src_rect.y = 3 * 16;
				actor[i].src_rect.x = (actor[i].frame / 8) * actor[i].dst_rect.w;
				break;

			case KIND_MOBILE_PLATFORM:
				switch (actor[i].direction)
				{
				case RIGHT:

					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x + actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x + actor[i].dst_rect.w > GAME_WINDOW_WIDTH)
						actor[i].direction = LEFT;

					// Colisi� amb el mapa, correcci� al ultim pixel bo i canvi de sentit
					if ((ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) % MAP_TILE_WIDTH);
						actor[i].direction = LEFT;
					}
					break;

				case LEFT:

					// Calculem la nova posici�
					actor[i].dst_rect.x = actor[i].dst_rect.x - actor[i].speed_x;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.x < 0)
						actor[i].direction = RIGHT;

					// Colisi� amb el mapa, correcci� al ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.x = actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x % MAP_TILE_WIDTH));
						actor[i].direction = RIGHT;
					}
					break;

				case DOWN:

					// Calculem la nova posici�
					actor[i].dst_rect.y = actor[i].dst_rect.y + actor[i].speed_y;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.y + actor[i].dst_rect.h > GAME_WINDOW_HEIGHT)
						actor[i].direction = UP;

					// Colisi� amb el mapa, correcci� al ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.y = actor[i].dst_rect.y - ((actor[i].dst_rect.y + actor[i].dst_rect.h) % MAP_TILE_WIDTH);
						actor[i].direction = UP;
					}
					break;

				case UP:

					// Calculem la nova posici�
					actor[i].dst_rect.y = actor[i].dst_rect.y - actor[i].speed_y;

					// Si eix per la vora, canvi de sentit
					if (actor[i].dst_rect.y < 0)
						actor[i].direction = DOWN;

					// Colisi� amb el mapa, correcci� al ultim pixel bo i canvi de sentit
					if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
						(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, actor[i].dst_rect.y / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
					{
						actor[i].dst_rect.y = actor[i].dst_rect.y + (MAP_TILE_WIDTH - (actor[i].dst_rect.y % MAP_TILE_WIDTH));
						actor[i].direction = DOWN;
					}
					break;
				}
				break;

			case KIND_DROP_GENERATOR:
				if (actor[i].timer > 0)
					actor[i].timer--;
				else
				// Si el contador arriba a 0, creem un actor KIND_DROP_ENEMY
				{
					actor[i].timer = 32000;
					Uint8 k = 0;
					while (actor[k].enabled)
						k++;
					CreateActor(actor[k], KIND_DROP_ENEMY, 0, actor[i].dst_rect.x, actor[i].dst_rect.y, 16, 16, 0, 8 * 16, 0, 2, 0, 0, DOWN, i);
					JA_PlaySound(game.sound_drop_enemy, 0);
				}

				// Animacio
				actor[i].frame = (actor[i].frame + 1) % 24;
				if (actor[i].timer > (DROP_TIMER - 25))
					// no el pintem. Posem el frame 6 que est� buit
					actor[i].src_rect.x = (6 * actor[i].dst_rect.w);
				else
					actor[i].src_rect.x = (actor[i].frame / 4) * actor[i].dst_rect.w;
				break;

			case KIND_DROP_ENEMY:
				// Calculem la nova posici�
				actor[i].dst_rect.y = actor[i].dst_rect.y + actor[i].speed_y;

				// Si eix per la vora, adios i avisa al pare
				if (actor[i].dst_rect.y + actor[i].dst_rect.h > GAME_WINDOW_HEIGHT)
				{
					actor[i].enabled = false;
					actor[actor[i].parent].timer = DROP_TIMER;
				}

				// Colisi� amb el mapa, correcci� al ultim pixel bo, transforma en KIND_DROP_SPLAT
				if ((ReadMapTile(actor[i].dst_rect.x / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND) ||
					(ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) / MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) / MAP_TILE_HEIGHT) != TILE_BACKGROUND))
				{
					actor[i].dst_rect.y = actor[i].dst_rect.y - ((actor[i].dst_rect.y + actor[i].dst_rect.h) % MAP_TILE_WIDTH);
					actor[i].kind = KIND_DROP_SPLAT;
					actor[i].frame = 0;
					actor[i].timer = 30;
					actor[i].src_rect.y = 11 * 16;
					JA_PlaySound(game.sound_drop_splat, 0);
				}

				// Animacio
				actor[i].frame = (actor[i].frame + 1) % 24;
				actor[i].src_rect.x = (actor[i].frame / 4) * actor[i].dst_rect.w;
				break;

			case KIND_DROP_SPLAT:
				// if (actor[i].timer > 0) then
				if (actor[i].frame < 23)
				// Si encara te temps, pintem la animaci�
				{
					actor[i].timer--;
					actor[i].frame = (actor[i].frame + 1) % 24;
					actor[i].src_rect.x = ((actor[i].frame / 4) + 0) * actor[i].dst_rect.w;
				}
				else
				{
					actor[i].enabled = false;
					actor[actor[i].parent].timer = DROP_TIMER;
				}
				break;

			case KIND_COIN:
				actor[i].frame = (actor[i].frame + 1) % 32;
				actor[i].src_rect.x = (actor[i].frame / 4) * actor[i].dst_rect.w;
				break;

			case KIND_HEART:
				actor[i].frame = (actor[i].frame + 1) % 32;
				actor[i].src_rect.x = (actor[i].frame / 4) * actor[i].dst_rect.w;
				break;

			case KIND_KEY:
				// actor[i].frame = (actor[i].frame + 1) % 32;
				// actor[i].src_rect.x = (actor[i].frame / 32) * actor[i].dst_rect.w;
				break;

			case KIND_LOCK:
				// actor[i].frame = (actor[i].frame + 1) % 32;
				// actor[i].src_rect.x = (actor[i].frame / 32) * actor[i].dst_rect.w;
				break;
			}
}

void SetPlayerDirection(int direction)
{
	if (player.direction != direction)
	{
		player.direction = direction;
		player.speed_x = 0;
	}
}

void MovePlayer(int direction)
{
	switch (direction)
	{
	case UP:
		// Si pot saltar, aleshores
		if ((OnFloor()) && (player.can_jump))
		{
			// Salta i ja no pot saltar (fins que toque terra i/o soltes el bot�)
			player.can_jump = false;

			// No estem quets
			player.standing = false;

			// Pilla velocitat negativa per a pujar cap amunt
			player.speed_y = -(player.jumpforce);

			// Calculem la nova posici�
			player.dst_rect.y = player.dst_rect.y + player.speed_y;

			// Soroll de saltar
			JA_PlaySound(player.sound_jump, 0);
		}

		// Nou frame d'animaci�
		if (player.direction == LEFT)
			SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_LEFT);
		else if (player.direction == RIGHT)
			SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_RIGHT);
		break;

	case RIGHT:
		// Per a poder dibuixar el bot en el sentit que toca
		SetPlayerDirection(RIGHT);

		// No estem quets
		player.standing = false;

		// Incrementem la velocitat horitzontal
		player.speed_x = std::min(player.speed_x + 1, int(MAX_SPEED));

		// Calculem la nova posici�
		player.dst_rect.x = player.dst_rect.x + ((player.speed_x / RATIO_SPEED) + 1);

		// Selecci� de l'animaci�
		if (player.speed_y == 0)
			// Animaci� de caminar
			SetPlayerAnimation(PLAYER_ANIMATION_WALKING_RIGHT);
		else
			// Animaci� de saltar
			SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_RIGHT);
		break;

	case LEFT:
		// Per a poder dibuixar el bot en el sentit que toca
		SetPlayerDirection(LEFT);

		// No estem quets
		player.standing = false;

		// Incrementem la velocitat horitzontal
		player.speed_x = std::min(player.speed_x + 1, int(MAX_SPEED));

		// Calculem la nova posici�
		player.dst_rect.x = player.dst_rect.x - ((player.speed_x / RATIO_SPEED) + 1);

		// Selecci� de l'animaci�
		if (player.speed_y == 0)
			// Animaci� de caminar
			SetPlayerAnimation(PLAYER_ANIMATION_WALKING_LEFT);
		else
			// Animaci� de saltar
			SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_LEFT);
		break;
	}
	// Calcul del frame d'animaci�
	Animate(player.animation[player.active_animation], player.src_rect);
}

void ApplyGravity()
{
	// Si toca piso aleshores
	if (OnFloor())
	{
		// Totes les forces verticals paren
		player.speed_y = 0;
		// Podem saltar
		player.can_jump = true;
	}
	else
	{
		// Si no toca piso aleshores s'incrementa la velocitat vertical
		player.speed_y = player.speed_y + _GRAVITY;

		// La velocitat no pot ser mai superior a la altura d'un tile del mapa, per a que no els atravesse
		// player.speed_y = std::max(std::min(player.speed_y, MAX_SPEED_Y), -(MAX_SPEED_Y));
		player.speed_y = std::min(player.speed_y, int(MAX_SPEED_Y));

		// Calculem la nova posici�
		player.dst_rect.y = player.dst_rect.y + player.speed_y;
	}
}

void DrawSprite(LTexture *sprite, SDL_Rect src_rect, SDL_Rect dst_rect)
{
	sprite->render(renderer, dst_rect.x, dst_rect.y, &src_rect);
}

void DrawMap()
{
	SDL_Rect src_rect1;
	SDL_Rect dst_rect1;

	src_rect1.w = MAP_TILE_WIDTH;
	src_rect1.h = MAP_TILE_HEIGHT;
	dst_rect1.w = MAP_TILE_WIDTH;
	dst_rect1.h = MAP_TILE_HEIGHT;

	for (Uint8 i = 0; i < ROOM_WIDTH_IN_TILES; i++)
		for (Uint8 j = 0; j < ROOM_HEIGHT_IN_TILES; j++)
		{
			src_rect1.x = (GetTile(i, j) % 16) * MAP_TILE_WIDTH;
			src_rect1.y = (GetTile(i, j) / 16) * MAP_TILE_HEIGHT;
			dst_rect1.x = i * MAP_TILE_WIDTH;
			dst_rect1.y = j * MAP_TILE_HEIGHT;
			map.sprite_tile->render(renderer, dst_rect1.x, dst_rect1.y, &src_rect1);
		}

	Uint8 i = 0;
	while (animated_tile[i].enabled)
	{
		src_rect1.x = ((animated_tile[i].index % 16) * MAP_TILE_WIDTH) + ((animated_tile[i].frame / 8) * MAP_TILE_WIDTH);
		src_rect1.y = (animated_tile[i].index / 16) * MAP_TILE_HEIGHT;
		dst_rect1.x = animated_tile[i].x;
		dst_rect1.y = animated_tile[i].y;
		animated_tile[i].frame = (animated_tile[i].frame + 1) % 16;
		map.sprite_tile->render(renderer, dst_rect1.x, dst_rect1.y, &src_rect1);
		i++;
	}
}

void DrawHud()
{
	// Pinta el fondo del marcador
	DrawSprite(hud.sprite, hud.src_rect, hud.dst_rect);

	// Pinta el numero de vides
	hud.bignum_src_rect.x = ((player.lifes % 100) / 10) * hud.bignum_src_rect.w;
	hud.bignum_dst_rect.y = 229;
	hud.bignum_dst_rect.x = 88;
	DrawSprite(hud.sprite, hud.bignum_src_rect, hud.bignum_dst_rect);

	hud.bignum_src_rect.x = (player.lifes % 10) * hud.bignum_src_rect.w;
	hud.bignum_dst_rect.x = 96;
	DrawSprite(hud.sprite, hud.bignum_src_rect, hud.bignum_dst_rect);

	// Pinta el numero de monedes
	hud.bignum_src_rect.x = (player.coins / 100) * hud.bignum_src_rect.w;
	hud.bignum_dst_rect.y = 229;
	hud.bignum_dst_rect.x = 258;
	DrawSprite(hud.sprite, hud.bignum_src_rect, hud.bignum_dst_rect);

	hud.bignum_src_rect.x = ((player.coins % 100) / 10) * hud.bignum_src_rect.w;
	hud.bignum_dst_rect.x = 258 + 8;
	DrawSprite(hud.sprite, hud.bignum_src_rect, hud.bignum_dst_rect);

	hud.bignum_src_rect.x = (player.coins % 10) * hud.bignum_src_rect.w;
	hud.bignum_dst_rect.x = 258 + 16;
	DrawSprite(hud.sprite, hud.bignum_src_rect, hud.bignum_dst_rect);

	if (prog.debug)
	{
		// Pinta el valor x,y del jugador
		// Centena de X
		hud.num_src_rect.x = (player.dst_rect.x / 100) * hud.num_src_rect.w;
		hud.num_dst_rect.y = 1;
		hud.num_dst_rect.x = 1;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Decena de X
		hud.num_src_rect.x = ((player.dst_rect.x % 100) / 10) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 5;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Unidad de X
		hud.num_src_rect.x = (player.dst_rect.x % 10) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 9;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Centena de Y
		hud.num_src_rect.x = (player.dst_rect.y / 100) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 17;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Decena de Y
		hud.num_src_rect.x = ((player.dst_rect.y % 100) / 10) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 21;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Unidad de Y
		hud.num_src_rect.x = (player.dst_rect.y % 10) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 25;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Pinta el valor de onfloor
		if (OnFloor())
			hud.num_src_rect.x = 1 * hud.num_src_rect.w;
		else
			hud.num_src_rect.x = 0 * hud.num_src_rect.w;
		hud.num_dst_rect.y = 1;
		hud.num_dst_rect.x = 33;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// tile_under_left_foot
		hud.num_src_rect.x = (ReadMapTile((player.dst_rect.x + 3) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) / MAP_TILE_HEIGHT)) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 37;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// tile_under_right_foot
		hud.num_src_rect.x = (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) / MAP_TILE_HEIGHT)) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 41;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// i_am_on_background
		Uint8 tile_on_left_foot = ReadMapTile((player.dst_rect.x + 3) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT);
		Uint8 tile_on_right_foot = ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT);
		bool i_am_on_background = ((tile_on_left_foot == TILE_BACKGROUND) && (tile_on_right_foot == TILE_BACKGROUND));
		if (i_am_on_background)
			hud.num_src_rect.x = 1 * hud.num_src_rect.w;
		else
			hud.num_src_rect.x = 0 * hud.num_src_rect.w;
		hud.num_dst_rect.x = 45;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Pinta el numero de habitación
		// Centena
		hud.num_src_rect.x = (map.room / 100) * hud.num_src_rect.w;
		hud.num_dst_rect.y = 1;
		hud.num_dst_rect.x = 49 + 4;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Decena
		hud.num_src_rect.x = ((map.room % 100) / 10) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 53 + 4;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);

		// Unidad
		hud.num_src_rect.x = (map.room % 10) * hud.num_src_rect.w;
		hud.num_dst_rect.x = 57 + 4;
		DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
	}
}

void CheckPlayerCollisionWithMap()
{
	// Si eix per baix, recalcula posici� i canvi de pantalla
	if (player.dst_rect.y > GAME_WINDOW_HEIGHT)
	{
		// Coloquem al jugador dalt de tot
		player.dst_rect.y = 1;

		// Canvi de pantalla
		LoadRoom(map.room + 12);
	}

	// Si eix per dalt, recalcula posici� i canvi de pantalla
	if ((player.dst_rect.y + player.dst_rect.h - 1) < 0)
	{
		// Recoloca el personat
		player.dst_rect.y = GAME_WINDOW_HEIGHT - player.dst_rect.h;

		// Canvi de pantalla
		LoadRoom(map.room - 12);
	}

	// Si eix per la vora, recalcula posici� i canvi de pantalla
	if (player.dst_rect.x > GAME_WINDOW_WIDTH)
	{
		// Coloquem al jugador en la entrada de la nova pantalla
		player.dst_rect.x = 0;

		// Canvi de pantalla
		LoadRoom(map.room + 1);
	}

	// Si eix per la vora, recalcula posici� i canvi de pantalla
	if ((player.dst_rect.x + player.dst_rect.w - 1) < 0)
	{
		// El posem al borde dret
		player.dst_rect.x = GAME_WINDOW_WIDTH - player.dst_rect.w;

		// Canvi de pantalla
		LoadRoom(map.room - 1);
	}

	// Mirem si colisionem cap avall i corregim
	Uint8 tile_on_left_foot = ReadMapTile((player.dst_rect.x + 3) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT);
	Uint8 tile_on_right_foot = ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT);

	bool i_am_on_platform = (tile_on_left_foot == TILE_PLATFORM) || (tile_on_right_foot == TILE_PLATFORM);
	bool i_am_on_travesable = (tile_on_left_foot == TILE_TRAVESABLE_PLATFORM) || (tile_on_right_foot == TILE_TRAVESABLE_PLATFORM);

	if ((player.was_on_background) && (player.speed_y > 0) && ((i_am_on_platform) || (i_am_on_travesable)))
	{
		// Corregim la posicio
		player.dst_rect.y = player.dst_rect.y - ((player.dst_rect.y + player.dst_rect.h - 1) % MAP_TILE_HEIGHT) - 1;

		// Ja podem saltar
		player.can_jump = true;
	}

	player.was_on_background = ((tile_on_left_foot == TILE_BACKGROUND) && (tile_on_right_foot == TILE_BACKGROUND));

	// Mirem si colisionem cap amunt i corregim
	if ((ReadMapTile((player.dst_rect.x + 3) / MAP_TILE_WIDTH, player.dst_rect.y / MAP_TILE_HEIGHT) == TILE_PLATFORM) ||
		(ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) / MAP_TILE_WIDTH, player.dst_rect.y / MAP_TILE_HEIGHT) == TILE_PLATFORM))
		// Corregim la posicio
		player.dst_rect.y = player.dst_rect.y + (MAP_TILE_HEIGHT - (player.dst_rect.y % MAP_TILE_HEIGHT));

	// Una vegada em permes la colisi� amunt o avall, al haver un marge de 3 pixels pot ser que estiguem dins d'una paret. S'ha de corregir aquest offset
	// Mirem les colisions laterals
	if ((ReadMapTile(player.dst_rect.x / MAP_TILE_WIDTH, player.dst_rect.y / MAP_TILE_HEIGHT) == TILE_PLATFORM) ||
		(ReadMapTile(player.dst_rect.x / MAP_TILE_WIDTH, (player.dst_rect.y + (player.dst_rect.h / 2)) / MAP_TILE_HEIGHT) == TILE_PLATFORM) ||
		(ReadMapTile(player.dst_rect.x / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT) == TILE_PLATFORM))
		player.dst_rect.x = player.dst_rect.x + (MAP_TILE_WIDTH - (player.dst_rect.x % MAP_TILE_WIDTH));

	if ((ReadMapTile((player.dst_rect.x + player.dst_rect.w - 1) / MAP_TILE_WIDTH, player.dst_rect.y / MAP_TILE_HEIGHT) == TILE_PLATFORM) || (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 1) / MAP_TILE_WIDTH, (player.dst_rect.y + (player.dst_rect.h / 2)) / MAP_TILE_HEIGHT) == TILE_PLATFORM) || (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 1) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) / MAP_TILE_HEIGHT) == TILE_PLATFORM))
		player.dst_rect.x = player.dst_rect.x - ((player.dst_rect.x + player.dst_rect.w) % MAP_TILE_WIDTH);

	// Comprovar si toca alguna part del mapa de les que maten
	if (ReadMapTile((player.dst_rect.x + 8) / MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 12) / MAP_TILE_HEIGHT) == TILE_KILLING_PLATFORM)
		if (player.enabled)
			KillPlayer();
}

void CheckPlayerCollisionWithActors()
{
	for (Uint8 i = 0; i < MAX_ACTORS; i++)
		if (actor[i].enabled)
			switch (actor[i].kind)
			{
			case KIND_FLYING_ENEMY:
			case KIND_WALKING_ENEMY:
			case KIND_DROP_ENEMY:
			case KIND_SPEED_ENEMY:
				if (((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)))
					if (player.enabled)
						KillPlayer();
				break;

			case KIND_COIN:
				if (((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)))
				{
					player.coins++;
					actor[i].enabled = false;
					SetActor((actor[i].dst_rect.x / 16), (actor[i].dst_rect.y / 16), 0);
					JA_PlaySound(player.sound_coin, 0);
				}
				break;

			case KIND_HEART:

				if (((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)))
				{
					player.lifes++;
					actor[i].enabled = false;
					SetActor((actor[i].dst_rect.x / 16), (actor[i].dst_rect.y / 16), 0);
					JA_PlaySound(player.sound_coin, 0);
				}
				break;

			case KIND_KEY:
				if (((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) && (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) && (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)))
				{
					player.key[actor[i].id] = true;
					actor[i].enabled = false;
					SetActor((actor[i].dst_rect.x / 16), (actor[i].dst_rect.y / 16), 0);
					JA_PlaySound(player.sound_coin, 0);
				}
				break;

			case KIND_LOCK:
				// Les colisions amb aquest actor no tenen en compte el ENEMY_HITBOX_REDUCTION
				// El jugador colisiona amb el actor per l'esquerra del jugador
				if (((actor[i].dst_rect.x + actor[i].dst_rect.w > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x + actor[i].dst_rect.w > player.dst_rect.x) && (actor[i].dst_rect.x + actor[i].dst_rect.w < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y > player.dst_rect.y) && (actor[i].dst_rect.y < player.dst_rect.y + player.dst_rect.h)))
				{
					// Si tenim clau
					if (player.key[actor[i].id])
					{
						actor[i].enabled = false;
						SetActor((actor[i].dst_rect.x / MAP_TILE_WIDTH), (actor[i].dst_rect.y / MAP_TILE_HEIGHT), 0);
					}
					// Si no tenim clau
					else
						player.dst_rect.x = player.dst_rect.x + (MAP_TILE_WIDTH - (player.dst_rect.x % MAP_TILE_WIDTH));
				}

				// El jugador colisiona amb el actor per la dreta del jugador
				if (((actor[i].dst_rect.x > player.dst_rect.x) && (actor[i].dst_rect.x < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y + actor[i].dst_rect.h > player.dst_rect.y) && (actor[i].dst_rect.y + actor[i].dst_rect.h < player.dst_rect.y + player.dst_rect.h)) ||
					((actor[i].dst_rect.x > player.dst_rect.x) && (actor[i].dst_rect.x < player.dst_rect.x + player.dst_rect.w) &&
					 (actor[i].dst_rect.y > player.dst_rect.y) && (actor[i].dst_rect.y < player.dst_rect.y + player.dst_rect.h)))
				{ // Si tenim clau
					if (player.key[actor[i].id])
					{
						actor[i].enabled = false;
						SetActor((actor[i].dst_rect.x / MAP_TILE_WIDTH), (actor[i].dst_rect.y / MAP_TILE_HEIGHT), 0);
					}
					// Si no tenim clau
					else
						player.dst_rect.x = player.dst_rect.x - ((player.dst_rect.x + player.dst_rect.w) % MAP_TILE_WIDTH);
				}
				break;
			}
}

void SetProgSection(Uint8 section)
{
	switch (section)
	{
	case SECTION_MENU:
		prog.section = SECTION_MENU;
		IniMenu();
		EndGame();
		break;

	case SECTION_GAME:
		prog.section = SECTION_GAME;
		IniGame(ZONE_VOLCANO);
		EndMenu();
		break;

	case SECTION_QUIT:
		prog.section = SECTION_QUIT;
		EndGame();
		EndMenu();
		break;
	}
}

void IniProgram()
{
	event = new SDL_Event();

	prog.music_enabled = true;
	prog.filter = true;
	SetProgSection(SECTION_MENU);
	prog.debug = false;

	/*if (prog.music_enabled)		// [TODO] Jail_Audio encara no permet canviar el volum
		Mix_VolumeMusic(100);
	else
		Mix_VolumeMusic(0); */

	loadTextureFromFile(prog.sprite, FILE_FILTER.c_str(), renderer);

	prog.src_rect.x = 0;
	prog.src_rect.y = 0;
	prog.src_rect.w = 640;
	prog.src_rect.h = 480;

	prog.dst_rect.x = 0;
	prog.dst_rect.y = 0;
	prog.dst_rect.w = 640;
	prog.dst_rect.h = 480;
}

void EndProgram()
{
	delete event;
	ClosePicture(prog.sprite);
	EndGame();
	EndMenu();
}

int main(int argc, char *args[])
{
	fullscreen = false;

	// Inicializa SDL
	//printf("Init SDL..\n");
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_HAPTIC);
	window = SDL_CreateWindow((WINDOW_TITLE + BUILD).c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
	SDL_RenderSetLogicalSize(renderer, 320, 240);

	// Inicia las variables con las rutas de los ficheros
	//printf("Init paths..\n");
	setExecutablePath(args[0]);

	// Inicializa el audio
	JA_Init(44100, AUDIO_S16, 2);

	allocatePointers();

	// Inicializa el programa
	IniProgram();

	// Color de relleno
	SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

	// Inicializa las variables generales
	quit = false;
	delta_time = SDL_GetTicks();

	// Bucle del programa
	while (!quit)
	{
		switch (prog.section)
		{
		case SECTION_GAME:
		{
			// Inicialitza habitaci�
			LoadRoom(STARTING_ROOM);

			// Conecta la musica
			JA_PlayMusic(game.music, -1);

			// Bucle de joc
			while (game.enabled)
			{
				while (SDL_PollEvent(event) > 0)
				{
					// Si arriva el event de tancar la aplicaci�, eixim del bucle
					if (event->type == SDL_QUIT)
					{
						quit = true;
						SetProgSection(SECTION_MENU);
						break;
					}
					else if ((event->type == SDL_KEYDOWN) && (event->key.repeat == 0))
						switch (event->key.keysym.scancode)
						{
						case SDL_SCANCODE_ESCAPE:
							SetProgSection(SECTION_MENU);
							break;

						case SDL_SCANCODE_F:
							if (fullscreen)
							{
								SDL_SetWindowFullscreen(window, 0);
								SDL_ShowCursor(1);
								fullscreen = false;
							}
							else
							{
								SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
								SDL_ShowCursor(0);
								fullscreen = true;
							}
							break;

						case SDL_SCANCODE_W:
							LoadRoom(map.room - 12);
							break;

						case SDL_SCANCODE_A:
							LoadRoom(map.room - 1);
							break;

						case SDL_SCANCODE_S:
							LoadRoom(map.room + 12);
							break;

						case SDL_SCANCODE_D:
							LoadRoom(map.room + 1);
							break;

						case SDL_SCANCODE_G:
							++_GRAVITY %= 2;
							break;

						case SDL_SCANCODE_H:
							player.lifes = 255;
							player.invulnerable = !player.invulnerable;
							break;

						case SDL_SCANCODE_M:
							prog.music_enabled = !prog.music_enabled;
							/*if (prog.music_enabled)	// [TODO] Jail_Audio encara no permet canviar el volum
								Mix_VolumeMusic(100);
							else
								Mix_VolumeMusic(0);*/
							break;

						case SDL_SCANCODE_T:
							IniPlayer();
							++starting_room %= 4;
							player.invulnerable = true;
							LoadRoom(starting_rooms_to_test[starting_room]);
							break;

						case SDL_SCANCODE_Z:
							player.dst_rect.y--;
							break;

						case SDL_SCANCODE_X:
							player.dst_rect.y++;
							break;

						case SDL_SCANCODE_F1:
							prog.debug = !prog.debug;
							break;

						case SDL_SCANCODE_F2:
							prog.filter = !prog.filter;
							break;

						default:
							break;
						}
				}

				if ((SDL_GetTicks() - delta_time) > GAME_SPEED)
				{
					// Agafar el array de tecles
					keys = SDL_GetKeyboardState(nullptr);

					// Mirem si esta apretant el bot� de saltar. Per tal d'evitar repeticions en aquest boto
					if (keys[SDL_SCANCODE_UP] == 0)
						player.jump_pressed_now = false;
					else
						player.jump_pressed_now = true;

					// Si el jugador est� deshabilitat, anem reduint el temps d'espera i canviant el frame de la animaci� de mort
					if (!player.enabled)
					{
						if (player.cooldown > 0)
						{
							player.cooldown--;
							Animate(player.animation[player.active_animation], player.src_rect);
						}
						else
						// Ha acabat el temps d'estar mort. Revivim al jugador
						{
							player.enabled = true;

							// Coloquem al jugador en el sentit que tenia quan va entrar a la habitaci�
							if (player.respawn_direction == LEFT)
							{
								SetPlayerAnimation(PLAYER_ANIMATION_STANDING_LEFT);
								player.direction = LEFT;
							}
							if (player.respawn_direction == RIGHT)
							{
								SetPlayerAnimation(PLAYER_ANIMATION_STANDING_RIGHT);
								player.direction = RIGHT;
							}

							// Coloquem al jugador en les coordenades per on va entrar
							player.dst_rect.x = std::min(player.respawn_x, GAME_WINDOW_WIDTH - player.dst_rect.w);
							player.dst_rect.y = player.respawn_y;

							// Recarreguem la habitaci�
							LoadRoom(map.room);

							if (player.lifes > 0)
								// Descontem una vida
								player.lifes--;
							else
								// Si no li queden vides, eixim al menu
								SetProgSection(SECTION_MENU);
						}
					}

					// Comprovem les tecles que ens interesen i actuem en consequ�ncia
					if ((keys[SDL_SCANCODE_RIGHT] == 1) && (player.enabled))
						MovePlayer(RIGHT);
					if ((keys[SDL_SCANCODE_LEFT] == 1) && (keys[SDL_SCANCODE_RIGHT] == 0) && (player.enabled))
						MovePlayer(LEFT);
					if ((keys[SDL_SCANCODE_UP] == 1) && (player.enabled) && (!player.jump_pressed_before))
						MovePlayer(UP);
					player.jump_pressed_before = player.jump_pressed_now;

					// Mirem si no estem fent cap a cap costat i reduim la velocitat horitzontal
					if ((keys[SDL_SCANCODE_RIGHT] == 0) && (keys[SDL_SCANCODE_LEFT] == 0) && (player.enabled))
					{
						player.speed_x = 0;

						// Estem quets
						player.standing = true;

						// Posem la animaci� d'estar quet si no estem saltant
						if (player.can_jump)
						{
							if (player.direction == LEFT)
								SetPlayerAnimation(PLAYER_ANIMATION_STANDING_LEFT);
							else if (player.direction == RIGHT)
								SetPlayerAnimation(PLAYER_ANIMATION_STANDING_RIGHT);
							Animate(player.animation[player.active_animation], player.src_rect);
						}
					}

					// Moure els actors
					MoveActors();

					// Apliquem la gravetat
					if (player.enabled)
						ApplyGravity();

					// Comprovar colisions amb els actors
					if (player.enabled)
						CheckPlayerCollisionWithActors();

					// Comprovar colisions amb el mapejat
					CheckPlayerCollisionWithMap();

					SDL_RenderSetLogicalSize(renderer, 320, 240);

					// Borrem pantalla
					SDL_RenderClear(renderer);

					// Pintem el fondo
					DrawSprite(map.background, map.src_rect, map.dst_rect);

					// Pinta el mapa
					DrawMap();

					// Pintem el jugador
					DrawSprite(player.sprite, player.src_rect, player.dst_rect);

					// Pintem els actors
					for (Uint8 i = 0; i < MAX_ACTORS; i++)
						if (actor[i].enabled)
							DrawSprite(map.sprite_actor, actor[i].src_rect, actor[i].dst_rect);

					// Pintem el marcador
					DrawHud();

					// Posem el filtro de pantalla
					if (prog.filter)
					{
						SDL_RenderSetLogicalSize(renderer, 640, 480);
						DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
					}

					// Mostrem la pantalla
					SDL_RenderPresent(renderer);

					delta_time = SDL_GetTicks();
				}
			}
			break;
		}

		case SECTION_MENU:
		{
			// Establir el color d'esborrat
			SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

			// Apaga la musica
			JA_StopMusic();

			while (menu.enabled)
			{
				// Bucle del menu
				while (SDL_PollEvent(event) > 0)
				{
					// Si arriva el event de tancar la aplicaci�, eixim del bucle
					if (event->type == SDL_QUIT)
					{
						quit = true;
						menu.enabled = false;
						break;
					}
					else if ((event->type == SDL_KEYDOWN) and (event->key.repeat == 0))
						switch (event->key.keysym.scancode)
						{
						case SDL_SCANCODE_ESCAPE:
							quit = true;
							SetProgSection(SECTION_QUIT);
							break;
							break;

						// (Des)Activa el mode de pantalla completa
						case SDL_SCANCODE_F:
							if (fullscreen)
							{
								SDL_SetWindowFullscreen(window, 0);
								SDL_ShowCursor(1);
								fullscreen = false;
							}
							else
							{
								SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
								SDL_ShowCursor(0);
								fullscreen = true;
							}
							break;

						// (Des)Activa la musica
						case SDL_SCANCODE_M:
							prog.music_enabled = !prog.music_enabled;
							/*if (prog.music_enabled)	// [TODO] Jail_Audio encara no permet canviar el volum
								Mix_VolumeMusic(100);
							else
								Mix_VolumeMusic(0);*/
							break;

						// (Des)Activa les scanlines
						case SDL_SCANCODE_F2:
							prog.filter = !prog.filter;
							break;

						// Inicia el joc
						case SDL_SCANCODE_RETURN:
							if (menu.timer > 99)
							{
								menu.timer = 99;
								JA_StopMusic();
								JA_StopChannel(-1);
								JA_PlaySound(menu.sound_start, 0);
								menu.frame = 0;
							}
							break;

						default:
							break;
						}
				}

				if ((SDL_GetTicks() - delta_time) > GAME_SPEED)
				{
					switch (menu.section)
					{
					case MENU_SECTION_MAIN:
					{
						if (menu.timer > 100)
						// Menu normal
						{
							menu.frame = (menu.frame + 1) % 30000;

							SDL_RenderSetLogicalSize(renderer, 320, 240);
							// Borrem pantalla
							SDL_RenderClear(renderer);

							// Pintem el fondo del menu
							// DrawSprite(menu.sprite, menu.src_rect_fondo, menu.dst_rect_fondo);

							// Pintem el logo DESPLEGA
							menu.dst_rect_logo_zoom.w = menu.dst_rect_logo.w;
							menu.dst_rect_logo_zoom.h = std::min(menu.dst_rect_logo_zoom.h + 4, menu.dst_rect_logo.h);
							menu.dst_rect_logo_zoom.x = menu.dst_rect_logo.x;
							menu.dst_rect_logo_zoom.y = menu.dst_rect_logo.y;

							DrawSprite(menu.sprite, menu.src_rect_logo, menu.dst_rect_logo_zoom);

							if (menu.frame == (154 / 4))
								JA_PlaySound(menu.sound_logo, 0);
							if (menu.frame == (300 / 4))
								// Conecta la musica
								JA_PlayMusic(menu.music, -1);

							if (menu.frame > (300 / 4))
							{
								// Pintem el text: PRESS RETURN TO START
								if ((menu.frame % 64) < 32)
									DrawSprite(menu.sprite, menu.src_rect_text, menu.dst_rect_text);

								// Pintem el text: JAILGAMES 2016
								DrawSprite(menu.sprite, menu.src_rect_text2, menu.dst_rect_text2);
							}
						}
						else
						// Menu havent apretat START/RETURN
						{
							menu.timer--;
							menu.frame = (menu.frame + 1) % 30000;

							// Borrem pantalla
							SDL_RenderSetLogicalSize(renderer, 320, 240);
							SDL_RenderClear(renderer);

							// Pintem el fondo del menu
							// DrawSprite(menu.sprite, menu.src_rect_fondo, menu.dst_rect_fondo);

							// Pintem el logo
							DrawSprite(menu.sprite, menu.src_rect_logo, menu.dst_rect_logo);

							// Pintem el text: PRESS RETURN TO START
							if ((menu.frame % 8) < 4)
								DrawSprite(menu.sprite, menu.src_rect_text, menu.dst_rect_text);

							// Pintem el text: JAILGAMES 2016
							DrawSprite(menu.sprite, menu.src_rect_text2, menu.dst_rect_text2);

							if (menu.timer == 0)
							{
								// prog.section = SECTION_GAME;
								// menu.enabled = false;
								// game.enabled = true;
								// menu.section = MENU_SECTION_ANIMATION;
								// menu.timer = 100;
							}
						}

						// Posem el filtro de pantalla
						if (prog.filter)
						{
							SDL_RenderSetLogicalSize(renderer, 640, 480);
							DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
						}

						// Mostrem la pantalla
						SDL_RenderPresent(renderer);

						delta_time = SDL_GetTicks();
					}

					case MENU_SECTION_ANIMATION:
					{
						// No hem pulsat el bot� d'start
						if (menu.timer > 100)
							// Animaci� inicial
							if (!menu.animation[0].loops)
							{
								// Borrem pantalla
								SDL_RenderSetLogicalSize(renderer, 320, 240);
								SDL_RenderClear(renderer);

								AnimateIntroMenu(menu.animation[0], menu.src_rect_animation);

								// Pintem la animacio
								DrawSprite(menu.sprite_animation, menu.src_rect_animation, menu.dst_rect_animation);

								// Posem el filtro de pantalla
								if (prog.filter)
								{
									SDL_RenderSetLogicalSize(renderer, 640, 480);
									DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
								}

								// Mostrem la pantalla
								SDL_RenderPresent(renderer);

								delta_time = SDL_GetTicks();
							}
							else
							// Animaci� segona en loop
							{
								if (JA_GetMusicState() != JA_MUSIC_PLAYING)
									JA_PlayMusic(menu.music, -1);

								// Borrem pantalla
								SDL_RenderSetLogicalSize(renderer, 320, 240);
								SDL_RenderClear(renderer);

								AnimateIntroMenu(menu.animation[1], menu.src_rect_animation);

								// Pintem la animacio
								DrawSprite(menu.sprite_animation, menu.src_rect_animation, menu.dst_rect_animation);

								// Pintem el text: PRESS RETURN TO START
								if ((menu.animation[1].timer % 64) < 32)
									DrawSprite(menu.sprite, menu.src_rect_text, menu.dst_rect_text);

								// Pintem el text: JAILGAMES 2016
								DrawSprite(menu.sprite, menu.src_rect_text2, menu.dst_rect_text2);

								// Posem el filtro de pantalla
								if (prog.filter)
								{
									SDL_RenderSetLogicalSize(renderer, 640, 480);
									DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
								}

								// Mostrem la pantalla
								SDL_RenderPresent(renderer);

								delta_time = SDL_GetTicks();
							}
						else
						// Hem pulsat el bot� d'start
						{
							JA_StopMusic();

							// Borrem pantalla
							SDL_RenderSetLogicalSize(renderer, 320, 240);
							SDL_RenderClear(renderer);

							AnimateIntroMenu(menu.animation[1], menu.src_rect_animation);

							// Pintem la animacio
							DrawSprite(menu.sprite_animation, menu.src_rect_animation, menu.dst_rect_animation);

							// Pintem el text: PRESS RETURN TO START
							if ((menu.animation[1].timer % 8) < 4)
								DrawSprite(menu.sprite, menu.src_rect_text, menu.dst_rect_text);

							// Pintem el text: JAILGAMES 2016
							DrawSprite(menu.sprite, menu.src_rect_text2, menu.dst_rect_text2);

							// Posem el filtro de pantalla
							if (prog.filter)
							{
								SDL_RenderSetLogicalSize(renderer, 640, 480);
								DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
							}

							// Mostrem la pantalla
							SDL_RenderPresent(renderer);

							delta_time = SDL_GetTicks();

							menu.timer--;
							if (menu.timer == 0)
							{
								SetProgSection(SECTION_GAME);
								menu.timer = 200;
							}
						}
						break;
					}
					}
				}
			}
			break;
		}
		}
	}
	// Finalitzar la m�sica, els samples i el audio
	CLOSE_SOUND(player.sound_jump);
	CLOSE_SOUND(player.sound_death);
	CLOSE_SOUND(player.sound_coin);
	CLOSE_SOUND(menu.sound_logo);
	CLOSE_SOUND(menu.sound_start);
	CLOSE_SOUND(game.sound_drop_enemy);
	CLOSE_SOUND(game.sound_drop_splat);

	JA_StopMusic();

	CLOSE_MUSIC(game.music);
	CLOSE_MUSIC(menu.music);

	// Mix_CloseAudio();

	EndProgram();

	// Destruir els sprites
	ClosePicture(prog.sprite);
	ClosePicture(player.sprite);
	ClosePicture(map.sprite_tile);
	ClosePicture(map.sprite_actor);
	ClosePicture(map.background);
	ClosePicture(menu.sprite);
	ClosePicture(menu.sprite_animation);
	ClosePicture(hud.sprite);

	deletePointers();

	// Destruir la finestra
	SDL_DestroyWindow(window);

	// Finalitzar SDL
	SDL_Quit();

	return 0;
}
