program Volcano;
{$IFDEF DARWIN}
	{$linkframework Cocoa}
	{$linkframework SDL2}
	{$linkframework OpenGL}
	{$linkframework SDL2_image}
	{$linkframework SDL2_mixer}
{$ELSE}
	{$APPTYPE GUI}
{$ENDIF}


// 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

uses sdl2, SDL2_image, SDL2_mixer;

const
	GAME_SPEED = 24; //16 = normal-rapid, 24 = normal. Quan menor, més ràpid
	
	UP =	0;
	DOWN =	2;
	RIGHT =	1;
	LEFT =	3;
	NONE =	4;

	MAP_TILE_HEIGHT =	16;
	MAP_TILE_WIDTH =	16;
	
	ROOM_WIDTH_IN_TILES =	20;
	ROOM_HEIGHT_IN_TILES =	14;
	
	GAME_WINDOW_WIDTH =		320;
	GAME_WINDOW_HEIGHT =	234;
	
	TEST_ROOM = 118;
	STARTING_ROOM = 161;//TEST_ROOM;
	STARTING_PLAYER_TILE_X = 5;
	STARTING_PLAYER_TILE_Y = 11;
	ENEMY_HITBOX_REDUCTION = 4;
	COOLDOWN_TIME =	50;
	GRAVITY = 1;
	MAX_SPEED_Y = 5;
	BASE_SPEED = 1;
	MAX_SPEED = 8;
	RATIO_SPEED = 8;
	DROP_TIMER = 100;
	
	TOP_COLLISION = 0;
	BOTTOM_COLLISION = 1;
	LEFT_COLLISION = 2;
	RIGHT_COLLISION = 3;
	NO_COLLISION = 4;
	
	MAX_ACTORS = 50;
	
	KIND_FLYING_ENEMY =		0;
	KIND_COIN =				1;
	KIND_HEART =			2;
	KIND_STATIC_ENEMY =		3;
	KIND_MOBILE_PLATFORM =	4;
	KIND_WALKING_ENEMY =	5;
	KIND_DROP_GENERATOR =	6;
	KIND_DROP_ENEMY =		7;
	KIND_DROP_SPLAT =		8;
	KIND_SPEED_ENEMY = 		9;
	KIND_KEY = 				10;
	KIND_LOCK = 			11;
	
	CODE_ENEMY_V1U = 208;
	CODE_ENEMY_V2U = 209;
	CODE_ENEMY_V3U = 210;
	CODE_ENEMY_V1D = 211;
	CODE_ENEMY_V2D = 212;
	CODE_ENEMY_V3D = 213;
	
	CODE_ENEMY_H1L = 214;
	CODE_ENEMY_H2L = 215;
	CODE_ENEMY_H3L = 216;
	CODE_ENEMY_H1R = 217;
	CODE_ENEMY_H2R = 218;
	CODE_ENEMY_H3R = 219;
	
	CODE_ENEMY_W1L = 224;
	CODE_ENEMY_W2L = 225;
	CODE_ENEMY_W3L = 226;
	CODE_ENEMY_W1R = 227;
	CODE_ENEMY_W2R = 228;
	CODE_ENEMY_W3R = 229;
	
	CODE_ENEMY_DRP = 230;
	
	CODE_ENEMY_SPL = 231;
	CODE_ENEMY_SPR = 232;
	
	CODE_COIN =			240;
	CODE_HEART =		241;
	CODE_KEY_RED =		242;
	CODE_LOCK_RED =		243;
	CODE_KEY_BLUE =		244;
	CODE_LOCK_BLUE =	245;
	CODE_KEY_GREEN =	246;
	CODE_LOCK_GREEN =	247;
	CODE_KEY_YELLOW =	248;
	CODE_LOCK_YELLOW =	249;
	
	MAX_ANIMATED_TILES = 200;
	
	TILE_BACKGROUND =			0;
	TILE_PLATFORM =				1;
	TILE_KILLING_PLATFORM =		2;
	TILE_ACTOR =				3;
	TILE_TRAVESABLE_PLATFORM =	4;
	
	PLAYER_ANIMATION_STANDING_LEFT =	0;
	PLAYER_ANIMATION_STANDING_RIGHT =	1;
	PLAYER_ANIMATION_WALKING_LEFT =		2;
	PLAYER_ANIMATION_WALKING_RIGHT =	3;
	PLAYER_ANIMATION_JUMPING_LEFT =		4;
	PLAYER_ANIMATION_JUMPING_RIGHT =	5;
	PLAYER_ANIMATION_DYING_LEFT =		6;
	PLAYER_ANIMATION_DYING_RIGHT =		7;
	
	SECTION_MENU = 0;
	SECTION_GAME = 1;
	SECTION_QUIT = 2;
	
	MENU_SECTION_MAIN = 0;
	MENU_SECTION_CREDITS = 1;
	MENU_SECTION_ANIMATION = 2;
	
	ZONE_SURFACE = 0;
	ZONE_VOLCANO = 1;
	
	WINDOW_TITLE = 			'Volcano v0005';
	BUILD =					'.05';
	FILE_MAP_VOLCANO =		'./data/volcano.map';
	FILE_TILES_VOLCANO =	'./data/gfx/tiles_volcano.png';
	FILE_TILES_SURFACE =	'./data/gfx/tiles_surface.png';
	FILE_BKG_SURFACE = 		'./data/gfx/bkg_surface.png';
	FILE_MENU =				'./data/gfx/menu.png';
	FILE_MENU_ANIMATION =	'./data/gfx/menu_animation.png';
	FILE_ACTORS = 			'./data/gfx/actors.png';
	FILE_PLAYER = 			'./data/gfx/player.png';
	FILE_HUD =				'./data/gfx/hud.png';
	FILE_FILTER =			'./data/gfx/filter.png';
	FILE_SOUND_JUMP =		'./data/sound/sound_player_jump.wav';
	FILE_SOUND_DEATH =		'./data/sound/sound_player_death.wav';
	FILE_SOUND_COIN =		'./data/sound/sound_player_coin.wav';
	FILE_SOUND_MENU_LOGO =	'./data/sound/sound_menu_logo.wav';
	FILE_SOUND_MENU_START = './data/sound/sound_menu_start.wav';
	FILE_SOUND_DROP_ENEMY =	'./data/sound/sound_drop_enemy.wav';
	FILE_SOUND_DROP_SPLAT = './data/sound/sound_drop_splat.wav';
	FILE_MUSIC_SURFACE =	'./data/music/music_surface.mp3';
	FILE_MUSIC_VOLCANO =	'./data/music/music_volcano.mp3';
	FILE_MUSIC_MENU =		'./data/music/music_menu.mp3';

type
	Tanimation = record
		num_frames:				byte;
		index:					byte;
		speed:					byte;
		timer:					longword;
		loops:					boolean; // salta a TRUE quan la animació es reinicia
		frame:					array [0 .. 49] of byte;
	end;
	
	Tprogram = record
		music_enabled:			boolean;
		filter:					boolean;
		section:				byte;
		debug:					boolean;
		sprite:					PSDL_Texture;
		src_rect:				TSDL_Rect;
		dst_rect:				TSDL_Rect;
	end;
	
	Tgame = record
		zone:					byte; // Zona en la que estem
		music:					PMix_Music;
		enabled:				boolean;
		sound_drop_enemy:		PMix_Chunk;
		sound_drop_splat:		PMix_Chunk;
	end;
	
	Tmenu = record
		section:				byte;
		sprite:					PSDL_Texture;
		sprite_animation:		PSDL_Texture;
		src_rect_fondo:			TSDL_Rect;
		dst_rect_fondo:			TSDL_Rect;
		src_rect_logo:			TSDL_Rect;
		dst_rect_logo:			TSDL_Rect;
		dst_rect_logo_zoom:		TSDL_Rect;
		src_rect_text:			TSDL_Rect;
		dst_rect_text:			TSDL_Rect;
		src_rect_text2:			TSDL_Rect;
		dst_rect_text2:			TSDL_Rect;
		music:					PMix_Music;
		sound_logo:				PMix_Chunk;
		sound_start:			PMix_Chunk;
		frame:					integer;
		enabled:				boolean;
		timer:					integer;
		animation:				array [0..1] of Tanimation;
		src_rect_animation:		TSDL_Rect;
		dst_rect_animation:		TSDL_Rect;
	end;
	
	Tplayer = record
		sprite:					PSDL_Texture;
		src_rect:				TSDL_Rect;
		dst_rect:				TSDL_Rect;
		direction:				byte;		// Sentit del desplaçament
		speed_x,
		speed_y:				integer;	// Quantitat de pixels a desplaçar
		jumpforce:				integer;	// Quantitat de pixels a desplaçar i velocitat que pilla al saltar
		active_animation:		byte;		// Index per al array d'animació
		animation:				array [0 .. 7] of Tanimation;
		can_jump:				boolean;	// Indica si el jugador pot saltar (FALSE si ja està saltant)
		jump_pressed_now,
		jump_pressed_before:	boolean;	// Indica si el botó de saltar està apretat, per evitar el autofire
		standing:				boolean;	// Indica si el jugador está quet.
		respawn_x,
		respawn_y:				integer;	// Coordenades per a reviure
		respawn_direction:		byte;		// Per a reviure en la mateixa direcció que s'entra a la habitació
		enabled:				boolean;	// Indica si pot rebre ordres
		cooldown:				integer;	// Temps d'inhabilitació
		lifes:					byte;		// Quantitat de vides
		coins:					integer;	// Quantitat de monedes
		key:					array [0..5] of boolean;
		sound_jump:				PMix_Chunk;
		sound_death:			PMix_Chunk;
		sound_coin:				PMix_Chunk;
		was_on_background:		boolean;	// Ens guardem si en l'anterior loop el tile sobre el qual teniem els nostres peus era background [27/05/2016] [DOC]
	end;
	
	Tactor = record
		src_rect:				TSDL_Rect;
		dst_rect:				TSDL_Rect;
		//animation:			Tanimation;
		kind:					byte;		// Tipus d'actor: enemic, moneda, clau, plataforma ...
		direction:				byte;		// Sentit del desplaçament
		id:						byte;
		speed_x,
		speed_y:				integer;	// Velocitat = quantitat de pixels a desplaçar
		frame:					integer;
		timer:					integer;
		enabled:				boolean;
		parent:					byte;		// Index al pare de l'actor
	end;
	
	Tanimated_tile = record
		enabled:				boolean;
		x, y:					integer;
		index:					integer;
		frame:					byte;
	end;
	
	Thud = record
		sprite:					PSDL_Texture;
		src_rect:				TSDL_Rect;
		dst_rect:				TSDL_Rect;
		num_src_rect:			TSDL_Rect;
		num_dst_rect:			TSDL_Rect;
		bignum_src_rect:		TSDL_Rect;
		bignum_dst_rect:		TSDL_Rect;
	end;

	Pmap = ^Tmap;
	Tmap = record
		sprite_tile:	PSDL_Texture;
		sprite_actor:	PSDL_Texture;
		background:		PSDL_Texture;
		src_rect:		TSDL_Rect;
		dst_rect:		TSDL_Rect;
		tile:			array of byte;
		actor:			array of byte;
		w, h:			byte;
		room:			byte;
	end;

var
	fullscreen:		boolean;
	window:			PSDL_Window;
	renderer:	 	PSDL_Renderer;
	prog:			Tprogram;
	menu:			Tmenu;
	game:			Tgame;
	player:			Tplayer;
	map:			Tmap;
	hud:			Thud;
	actor:			array [0..MAX_ACTORS - 1] of Tactor;
	animated_tile:	array [0..MAX_ANIMATED_TILES - 1] of Tanimated_tile;
	e:				TSDL_Event;
	keys:			PUInt8;
	quit:			boolean;
	delta_time:		Uint32;
	i:				byte;
	
function max(a,b:integer):integer;
begin
	if a > b then max:=a else max:=b;
end;

function min(a,b:integer):integer;
begin
	if a < b then min:=a else min:=b;
end;

function OpenPicture(name: PChar) : PSDL_Texture;
var
	image:		PSDL_Surface;
	texture:	PSDL_Texture;
begin
	image := IMG_Load(name);
	texture := SDL_CreateTextureFromSurface(renderer, image);
	SDL_FreeSurface(image);
	OpenPicture := texture;
end;

procedure CloseSound(var sound: PMix_Chunk);
begin
	if sound <> nil then
		Mix_FreeChunk(sound);
	sound := nil;
end;

procedure CloseMusic(var music: PMix_Music);
begin
	if music <> nil then
		Mix_FreeMusic(music);
	music := nil;
end;

procedure ClosePicture(var picture: PSDL_Texture);
begin
	if picture <> nil then
		SDL_DestroyTexture(picture);
	picture := nil;
end;

function GetTile(x, y: byte): byte;
// Entrada: coordenades en tiles relatives a la habitació actual
// Eixida: el valor del byte
var
	room_x, room_y: byte;
begin
	room_x := (map.room mod 12) * ROOM_WIDTH_IN_TILES;
	room_y := (map.room div 12) * ROOM_HEIGHT_IN_TILES;
	GetTile := map.tile[(room_x + x ) + (room_y + y) * map.w];
end;

function ReadMapTile(x, y: byte): byte;
begin
	case GetTile(x,y) of
		000 .. 063:	ReadMapTile := TILE_BACKGROUND;
		064 .. 143:	ReadMapTile := TILE_PLATFORM;
		144 .. 175: ReadMapTile := TILE_TRAVESABLE_PLATFORM;
		176 .. 207:	ReadMapTile := TILE_KILLING_PLATFORM;
		208 .. 255:	ReadMapTile := TILE_ACTOR;
		else ReadMapTile := TILE_BACKGROUND;
	end;
end;

function GetActor(x, y: byte): byte;
var
	room_x, room_y	: byte;
begin
	room_x := (map.room mod 12) * ROOM_WIDTH_IN_TILES;
	room_y := (map.room div 12) * ROOM_HEIGHT_IN_TILES;
	GetActor := map.actor[(room_x + x) + (room_y + y) * map.w];
end;

Procedure SetActor(x, y, valor: byte);
var
	room_x, room_y	: byte;
begin
	room_x := (map.room mod 12) * ROOM_WIDTH_IN_TILES;
	room_y := (map.room div 12) * ROOM_HEIGHT_IN_TILES;
	map.actor[(room_x + x) + (room_y + y) * map.w] := valor;
end;

procedure SetMapGFX(zone: byte);
begin
	case zone of
	ZONE_SURFACE:
		begin
			map.sprite_tile := OpenPicture(FILE_TILES_SURFACE);
			map.background := OpenPicture(FILE_BKG_SURFACE);
		end;
		
	ZONE_VOLCANO:
		begin
			map.sprite_tile := OpenPicture(FILE_TILES_VOLCANO);
			map.background := OpenPicture(FILE_BKG_SURFACE);
		end;
	end;
end;

procedure SetMapMusic(zone: byte);
begin
	case zone of
	ZONE_SURFACE:
		game.music := Mix_LoadMUS(FILE_MUSIC_SURFACE);
		
	ZONE_VOLCANO:
		game.music := Mix_LoadMUS(FILE_MUSIC_VOLCANO);
	end;
end;

function CheckZoneChange(room: integer): boolean;
var
	zone:	byte;
begin
	case room of
	0 .. 23:
		zone := ZONE_SURFACE;
	24 .. 255:
		zone := ZONE_VOLCANO;
	end;
	
	if (zone = game.zone) then
		CheckZoneChange := FALSE
	else
		CheckZoneChange := TRUE;
end;

procedure SetZone(room: integer);
begin
	case room of
	0 .. 23:
		game.zone := ZONE_SURFACE;
	
	24 .. 255:
		game.zone := ZONE_VOLCANO;
	end;
	
	SetMapGFX(game.zone);
	SetMapMusic(game.zone);
	Mix_PlayMusic(game.music, -1);
end;

procedure SetPlayerAnimation(anim: byte);
begin
	if (anim <> player.active_animation) then
		begin
			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;
		end;
end;

procedure Animate(var a:Tanimation; var s:TSDL_Rect);
begin
	// 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) then
		a.loops := TRUE
	else
		a.loops := FALSE;
			
	a.timer := (a.timer + 1) mod (a.num_frames * a.speed);
	a.index := a.timer div a.speed;
	s.x := (a.frame[a.index])  * s.w;
end;

procedure AnimateIntroMenu(var a:Tanimation; var s:TSDL_Rect);
begin
	// 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) then
		a.loops := TRUE
	else
		a.loops := FALSE;
			
	a.timer := (a.timer + 1) mod (a.num_frames * a.speed);
	a.index := a.timer div a.speed;
	s.x := (a.frame[a.index] mod 4)  * s.w;
	s.y := (a.frame[a.index] div 4)  * s.h;
end;

procedure CreateActor(var a : Tactor; kind, id : byte; dstx, dsty, dstw, dsth, srcx, srcy, sx, sy, timer, frame : smallint; direction, parent : byte);
begin
	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;
end;

procedure LoadMap(map:Pmap);
var
	f:					File;
	numread:			Word;
	size:				array[0..1] of byte;
begin
	Assign(f, FILE_MAP_VOLCANO);
	Reset(f, 1);
	BlockRead(f, size, 2, numread);
	map^.w := size[0];
	map^.h := size[1];
	SetLength(map^.tile, map^.w * map^.h);
	SetLength(map^.actor, map^.w * map^.h);
	BlockRead(f, map^.tile[0], map^.w * map^.h, numread);
	BlockRead(f, map^.actor[0], map^.w * map^.h, numread);
	Close(f);
end;

procedure LoadRoom(num:integer);
var
	i, j, k:	integer;
begin
	if (CheckZoneChange(num)) then
		begin
			SetZone(num);
		end;
	
	// Coloquem el numero d'habitació corresponent al mapa
	map.room := 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 i:=0 to MAX_ANIMATED_TILES - 1 do
		animated_tile[i].enabled := FALSE;
	
	// Escanejem la habitació en busca de tiles animats
	k := 0;
	for i:=0 to (ROOM_WIDTH_IN_TILES - 1) do
		for j:=0 to (ROOM_HEIGHT_IN_TILES - 1) do
			case GetTile(i, j) of
				48 .. 63, 128 .. 143, 160..175, 192..207:
				begin
					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;
					inc(k);
				end;
			end;
	
	// Esborrem la llista d'actors actius
	for i:=0 to MAX_ACTORS - 1 do
		actor[i].enabled := FALSE;
	
	// Escanejem la habitació en busca d'actors per afegirlos a la llista d'actors actius
	k := 0;
	for i:=0 to (ROOM_WIDTH_IN_TILES - 1) do
		for j:=0 to (ROOM_HEIGHT_IN_TILES - 1) do
			begin
				case GetActor(i, j) of
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
									
					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);
					
					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);
					
					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);
									
					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);
					
					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);
					
					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);
									
					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);
					
					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);
					
					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);
									
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					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);
					
					else
						dec(k);
				end;
				inc(k);
			end;
end;

procedure IniMenu();
begin
	menu.enabled := TRUE;
	menu.section := MENU_SECTION_ANIMATION;
	
	menu.music := Mix_LoadMUS(FILE_MUSIC_MENU);
	menu.sound_logo := Mix_LoadWAV(FILE_SOUND_MENU_LOGO);
	menu.sound_start := Mix_LoadWAV(FILE_SOUND_MENU_START);
		
	menu.sprite := OpenPicture(FILE_MENU);
	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) div 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) div 2;
	menu.dst_rect_text2.y := 210;
	menu.dst_rect_text2.w := 55;
	menu.dst_rect_text2.h := 5;
	
	// Animació
	menu.sprite_animation := OpenPicture(FILE_MENU_ANIMATION);
	
	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;
end;

procedure EndMenu();
begin
	CloseSound(menu.sound_logo);
	CloseSound(menu.sound_start);
	CloseMusic(menu.music);
	ClosePicture(menu.sprite);
	ClosePicture(menu.sprite_animation);
	menu.enabled:= FALSE;
end;

procedure IniActors();
var
	i:	byte;
begin
	for i:=0 to MAX_ACTORS - 1 do
		actor[i].enabled := FALSE;
	map.sprite_actor := OpenPicture(FILE_ACTORS);
end;

procedure IniAnimatedTiles();
var
	i:	byte;
begin
	for i:=0 to MAX_ANIMATED_TILES - 1 do
		animated_tile[i].enabled := FALSE;
end;

procedure IniMap();
begin
	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(@map);
end;

procedure EndMap();
begin
	ClosePicture(map.sprite_tile);
	ClosePicture(map.sprite_actor);
	ClosePicture(map.background);
end;

procedure IniPlayer();
var
	i:	byte;
begin
	player.sprite := OpenPicture(FILE_PLAYER);
	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.jumpforce := 10;
	player.active_animation := 0;
	player.enabled := TRUE;
	player.cooldown := 0;
	player.lifes := 10;
	player.coins := 0;
	for i:=0 to 5 do player.key[i] := FALSE;
	player.sound_jump := Mix_LoadWAV(FILE_SOUND_JUMP);
	player.sound_death := Mix_LoadWAV(FILE_SOUND_DEATH);
	player.sound_coin := Mix_LoadWAV(FILE_SOUND_COIN);
	
	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];
end;

procedure EndPlayer();
begin
	ClosePicture(player.sprite);
	CloseSound(player.sound_jump);
	CloseSound(player.sound_death);
	CloseSound(player.sound_coin);
end;

procedure IniHud();
begin
	hud.sprite := OpenPicture(FILE_HUD);
	hud.src_rect.x := 0;
	hud.src_rect.y := 0;
	hud.src_rect.w := 320;
	hud.src_rect.h := 16;
	
	hud.dst_rect.x := 0;
	hud.dst_rect.y := 224;
	hud.dst_rect.w := 320;
	hud.dst_rect.h := 16;
	
	hud.num_src_rect.x := 0;
	hud.num_src_rect.y := 16;
	hud.num_src_rect.w := 5;
	hud.num_src_rect.h := 5;
	
	hud.num_dst_rect.x := 0;
	hud.num_dst_rect.y := 16;
	hud.num_dst_rect.w := 5;
	hud.num_dst_rect.h := 5;
	
	hud.bignum_src_rect.x := 0;
	hud.bignum_src_rect.y := 21;
	hud.bignum_src_rect.w := 7;
	hud.bignum_src_rect.h := 7;
	
	hud.bignum_dst_rect.x := 0;
	hud.bignum_dst_rect.y := 21;
	hud.bignum_dst_rect.w := 7;
	hud.bignum_dst_rect.h := 7;
end;

procedure EndHud();
begin
	ClosePicture(hud.sprite);
end;

procedure IniGame(zone: byte);
begin
	game.sound_drop_enemy := Mix_LoadWAV(FILE_SOUND_DROP_ENEMY);
	game.sound_drop_splat := Mix_LoadWAV(FILE_SOUND_DROP_SPLAT);
	game.enabled := TRUE;
	game.zone := zone;
	
	// Inicialitzar jugador
	IniPlayer();
	
	// Inicialitza hud
	IniHud();
	
	// Establir el color d'esborrat
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

	// Inicialitza actors
	IniActors();

	// Inicialitza tiles animats
	IniAnimatedTiles();
		
	// Inicialitza mapa
	IniMap();
	SetMapGFX(zone);
	SetMapMusic(zone);
end;

procedure EndGame();
begin
	EndPlayer();
	EndHud();
	EndMap();
	CloseSound(game.sound_drop_enemy);
	CloseSound(game.sound_drop_splat);
	CloseMusic(game.music);
	game.enabled := FALSE;
end;

procedure KillPlayer();
begin
	player.enabled := FALSE;
	player.cooldown := COOLDOWN_TIME;
	
	// Establir animació de mort
	if (player.direction = LEFT) then
		SetPlayerAnimation(PLAYER_ANIMATION_DYING_LEFT)
	else
		SetPlayerAnimation(PLAYER_ANIMATION_DYING_RIGHT);
		
	
	Mix_PlayChannel(-1, player.sound_death, 0);
end;

function OnFloor():boolean;
//[27/08/2016] [DOC] [BEGIN]
var
	tile_on_right_foot,    tile_on_left_foot,
	tile_under_right_foot, tile_under_left_foot		: byte;
	
	i_am_above_platform,   i_am_above_travesable,
	i_am_on_background								: boolean;
begin
	tile_under_left_foot  := ReadMapTile((player.dst_rect.x + 3				       ) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div MAP_TILE_HEIGHT);
	tile_under_right_foot := ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div MAP_TILE_HEIGHT);
	
	i_am_above_platform   := (tile_under_left_foot = TILE_PLATFORM) 		   or (tile_under_right_foot = TILE_PLATFORM);
	i_am_above_travesable := (tile_under_left_foot = TILE_TRAVESABLE_PLATFORM) or (tile_under_right_foot = TILE_TRAVESABLE_PLATFORM);

	tile_on_left_foot  := ReadMapTile((player.dst_rect.x + 3				    ) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h-1) div MAP_TILE_HEIGHT);
	tile_on_right_foot := ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h-1) div MAP_TILE_HEIGHT);
	
	i_am_on_background := (tile_on_left_foot = TILE_BACKGROUND) and (tile_on_right_foot = TILE_BACKGROUND);
	
	if ( ( i_am_above_platform or i_am_above_travesable ) and i_am_on_background ) then
		OnFloor := TRUE
	else
		OnFloor := FALSE;
//[27/08/2016] [DOC] [END]
	
	{if (ReadMapTile((player.dst_rect.x + 3				      ) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + 3					  ) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div MAP_TILE_HEIGHT) = TILE_TRAVESABLE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div MAP_TILE_HEIGHT) = TILE_TRAVESABLE_PLATFORM) then
		OnFloor := TRUE
	else
		OnFloor := FALSE;}
end;

procedure MoveActors();
var
	i, k:	byte;
begin
	for i:=0 to MAX_ACTORS - 1 do
		if actor[i].enabled then
			case actor[i].kind of
				KIND_FLYING_ENEMY:
				begin
					case actor[i].direction of
						RIGHT:
							begin
								// 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) then
									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) div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
								or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
									begin
										actor[i].dst_rect.x := actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) mod MAP_TILE_WIDTH);
										actor[i].direction := LEFT;
									end;
							end;
										
						LEFT:
						begin
							// 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 then
								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 div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.x := actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x mod MAP_TILE_WIDTH));
									actor[i].direction := RIGHT;
								end;
						end;
										
						DOWN:
						begin
							// 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) then
								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 div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.y := actor[i].dst_rect.y - ((actor[i].dst_rect.y + actor[i].dst_rect.h) mod MAP_TILE_WIDTH);
									actor[i].direction := UP;
								end;
						end;
										
						UP:
						begin
							// 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) then
								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 div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.y := actor[i].dst_rect.y + (MAP_TILE_WIDTH - (actor[i].dst_rect.y mod MAP_TILE_WIDTH));
									actor[i].direction := DOWN;
								end;
						end;					
					end;
								
					actor[i].frame := (actor[i].frame + 1) mod 24;
					if (actor[i].direction = UP) then
						actor[i].src_rect.y := 4 * 16;
					if (actor[i].direction = DOWN) then
						actor[i].src_rect.y := 5 * 16;
					if (actor[i].direction = LEFT) then
						actor[i].src_rect.y := 7 * 16;
					if (actor[i].direction = RIGHT) then
						actor[i].src_rect.y := 6 * 16;
					actor[i].src_rect.x := (actor[i].frame div 4) * actor[i].dst_rect.w;
				end;
				
				KIND_WALKING_ENEMY:
				begin
					case actor[i].direction of
						RIGHT:
							begin
								// 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) then
									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) div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
								or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
									begin
										actor[i].dst_rect.x := actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) mod MAP_TILE_WIDTH);
										actor[i].direction := LEFT;
									end;
									
								// 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) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) div MAP_TILE_HEIGHT) <> TILE_PLATFORM) then
									actor[i].direction := LEFT;
							end;
										
						LEFT:
						begin
							// 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 then
								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 div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.x := actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x mod MAP_TILE_WIDTH));
									actor[i].direction := RIGHT;
								end;
								
							// Arriba a la vora, correcció a l'ultim pixel bo i canvi de sentit
							if (ReadMapTile((actor[i].dst_rect.x + 3) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) div MAP_TILE_HEIGHT) <> TILE_PLATFORM) then
								actor[i].direction := RIGHT;
						end;
					end;
					
					// Animacio
					actor[i].frame := (actor[i].frame + 1) mod 48;
					if (actor[i].direction = LEFT) then
						actor[i].src_rect.y := 1 * 16
					else
						actor[i].src_rect.y := 0 * 16;
					actor[i].src_rect.x := (actor[i].frame div 8) * actor[i].dst_rect.w;
				end;
				
				KIND_SPEED_ENEMY:
				begin
					case actor[i].direction of
						RIGHT:
							begin
								// 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)
								and (actor[i].dst_rect.y + 8 < player.dst_rect.y + player.dst_rect.h - 1)
								and (player.can_jump) then
									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) then
									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) div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
								or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
									begin
										actor[i].dst_rect.x := actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) mod MAP_TILE_WIDTH);
										actor[i].direction := LEFT;
									end;
									
								// 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) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) div MAP_TILE_HEIGHT) <> TILE_PLATFORM) then
									actor[i].direction := LEFT;
							end;
										
						LEFT:
						begin
							// 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)
							and (actor[i].dst_rect.y + 8 < player.dst_rect.y + player.dst_rect.h - 1)
							and (player.can_jump) then
								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 then
								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 div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.x := actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x mod MAP_TILE_WIDTH));
									actor[i].direction := RIGHT;
								end;
								
							// Arriba a la vora, correcció a l'ultim pixel bo i canvi de sentit
							if (ReadMapTile((actor[i].dst_rect.x + 3) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h) div MAP_TILE_HEIGHT) <> TILE_PLATFORM) then
								actor[i].direction := RIGHT;
						end;
					end;
					
					// Animacio
					actor[i].frame := (actor[i].frame + 1) mod 48;
					if (actor[i].direction = LEFT) then
						actor[i].src_rect.y := 2 * 16
					else
						actor[i].src_rect.y := 3 * 16;
					actor[i].src_rect.x := (actor[i].frame div 8) * actor[i].dst_rect.w;
				end;
				
				KIND_MOBILE_PLATFORM:
				begin
					case actor[i].direction of
						RIGHT:
						begin
							// 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) then
								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) div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.x := actor[i].dst_rect.x - ((actor[i].dst_rect.x + actor[i].dst_rect.w) mod MAP_TILE_WIDTH);
									actor[i].direction := LEFT;
								end;
						end;
								
						LEFT:
						begin
							// 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) then
								actor[i].direction := RIGHT;
							
							// Colisió amb el mapa, correcció al ultim pixel bo i canvi de sentit
							if (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.x := actor[i].dst_rect.x + (MAP_TILE_WIDTH - (actor[i].dst_rect.x mod MAP_TILE_WIDTH));
									actor[i].direction := RIGHT;
								end;
						end;
								
						DOWN:
						begin
							// 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) then
								actor[i].direction := UP;
							
							// Colisió amb el mapa, correcció al ultim pixel bo i canvi de sentit
							if (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.y := actor[i].dst_rect.y - ((actor[i].dst_rect.y + actor[i].dst_rect.h) mod MAP_TILE_WIDTH);
									actor[i].direction := UP;
								end;
						end;
								
						UP:
						begin
							// 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) then
								actor[i].direction := DOWN;
							
							// Colisió amb el mapa, correcció al ultim pixel bo i canvi de sentit
							if (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
							or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, actor[i].dst_rect.y div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
								begin
									actor[i].dst_rect.y := actor[i].dst_rect.y + (MAP_TILE_WIDTH - (actor[i].dst_rect.y mod MAP_TILE_WIDTH));
									actor[i].direction := DOWN;
								end;
						end;					
					end;
				end;
				
				KIND_DROP_GENERATOR:
				begin
					if (actor[i].timer > 0) then
						dec(actor[i].timer)
					else
						// Si el contador arriba a 0, creem un actor KIND_DROP_ENEMY
						begin
							actor[i].timer := 32000;
							k := 0;
							while (actor[k].enabled) do inc(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);
							Mix_PlayChannel(-1, game.sound_drop_enemy, 0);
						end;
					
					// Animacio
					actor[i].frame := (actor[i].frame + 1) mod 24;
					if (actor[i].timer > (DROP_TIMER - 25)) then
						// 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 div 4) * actor[i].dst_rect.w;
				end;
				
				KIND_DROP_ENEMY:
				begin
					// 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) then
						begin
							actor[i].enabled := FALSE;
							actor[actor[i].parent].timer := DROP_TIMER;
						end;
					
					// Colisió amb el mapa, correcció al ultim pixel bo, transforma en KIND_DROP_SPLAT
					if (ReadMapTile(actor[i].dst_rect.x div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND)
					or (ReadMapTile((actor[i].dst_rect.x + actor[i].dst_rect.w - 1) div MAP_TILE_WIDTH, (actor[i].dst_rect.y + actor[i].dst_rect.h - 1) div MAP_TILE_HEIGHT) <> TILE_BACKGROUND) then
						begin
							actor[i].dst_rect.y := actor[i].dst_rect.y - ((actor[i].dst_rect.y + actor[i].dst_rect.h) mod MAP_TILE_WIDTH);
							actor[i].kind := KIND_DROP_SPLAT;
							actor[i].frame := 0;
							actor[i].timer := 30;
							actor[i].src_rect.y := 11 * 16;
							Mix_PlayChannel(-1, game.sound_drop_splat, 0);
						end;
						
					// Animacio
					actor[i].frame := (actor[i].frame + 1) mod 24;
					actor[i].src_rect.x := (actor[i].frame div 4) * actor[i].dst_rect.w;
				end;
				
				KIND_DROP_SPLAT:
				begin
					//if (actor[i].timer > 0) then
					if (actor[i].frame < 23) then
						// Si encara te temps, pintem la animació
						begin
							dec(actor[i].timer);
							actor[i].frame := (actor[i].frame + 1) mod 24;
							actor[i].src_rect.x := ((actor[i].frame div 4) + 0) * actor[i].dst_rect.w;
						end
					else
						begin
							actor[i].enabled := FALSE;
							actor[actor[i].parent].timer := DROP_TIMER;
						end;
				end;
					
				KIND_COIN:
				begin
					actor[i].frame := (actor[i].frame + 1) mod 32;
					actor[i].src_rect.x := (actor[i].frame div 4) * actor[i].dst_rect.w;
				end;
					
				KIND_HEART:
				begin
					actor[i].frame := (actor[i].frame + 1) mod 32;
					actor[i].src_rect.x := (actor[i].frame div 4) * actor[i].dst_rect.w;
				end;
				
				KIND_KEY:
				begin
					//actor[i].frame := (actor[i].frame + 1) mod 32;
					//actor[i].src_rect.x := (actor[i].frame div 32) * actor[i].dst_rect.w;
				end;
				
				KIND_LOCK:
				begin
					//actor[i].frame := (actor[i].frame + 1) mod 32;
					//actor[i].src_rect.x := (actor[i].frame div 32) * actor[i].dst_rect.w;
				end;
			end;
end;

procedure SetPlayerDirection(direction: integer);
begin
	if (direction <> player.direction) then
		begin
			player.direction := direction;
			player.speed_x := 0;
		end;
end;

procedure MovePlayer(direction: integer);
begin
	case direction of
		UP:
		begin
			// Si pot saltar, aleshores
			if (OnFloor and player.can_jump) then
				begin
					// 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
					Mix_PlayChannel(-1, player.sound_jump, 0);
				end;
				
			// Nou frame d'animació
			if (player.direction = LEFT) then
				SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_LEFT)
			else
				if (player.direction = RIGHT) then
					SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_RIGHT);
		end;
				
		RIGHT:
		begin
			// 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 := min(player.speed_x + 1, MAX_SPEED);
			
			// Calculem la nova posició
			player.dst_rect.x := player.dst_rect.x + ((player.speed_x div RATIO_SPEED) + 1);
			
			// Selecció de l'animació
			if (player.speed_y = 0) then
				// Animació de caminar
				SetPlayerAnimation(PLAYER_ANIMATION_WALKING_RIGHT)
			else
				// Animació de saltar
				SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_RIGHT);
		end;
				
		LEFT :
		begin
			// 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 := min(player.speed_x + 1, MAX_SPEED);
			
			// Calculem la nova posició
			player.dst_rect.x := player.dst_rect.x - ((player.speed_x div RATIO_SPEED) + 1);
				
			// Selecció de l'animació
			if (player.speed_y = 0) then
				// Animació de caminar
				SetPlayerAnimation(PLAYER_ANIMATION_WALKING_LEFT)
			else
				// Animació de saltar
				SetPlayerAnimation(PLAYER_ANIMATION_JUMPING_LEFT);
		end;
	end;
	
	// Calcul del frame d'animació
	Animate(player.animation[player.active_animation], player.src_rect);
end;

procedure ApplyGravity();
begin
	// Si toca piso aleshores
	if (OnFloor) then
		begin
			// Totes les forces verticals paren
			player.speed_y := 0;
			// Podem saltar
			player.can_jump := TRUE;
		end
	else
		begin
			// 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 := max(min(player.speed_y, MAX_SPEED_Y), -(MAX_SPEED_Y));
			player.speed_y := min(player.speed_y, MAX_SPEED_Y);
			
			// Calculem la nova posició
			player.dst_rect.y := player.dst_rect.y + player.speed_y;
		end;
end;

procedure DrawSprite (sprite:PSDL_Texture; src_rect, dst_rect: TSDL_Rect);
begin
	SDL_RenderCopy(renderer, sprite, @src_rect, @dst_rect);
end;

procedure DrawMap(map:Tmap);
var
	i, j:	byte;
	src_rect1:	TSDL_Rect;
	dst_rect1:	TSDL_Rect;
begin
	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 i:=0 to (ROOM_WIDTH_IN_TILES - 1) do
		for j:=0 to (ROOM_HEIGHT_IN_TILES - 1) do
			begin
				src_rect1.x := (GetTile(i, j) mod 16) * MAP_TILE_WIDTH;
				src_rect1.y := (GetTile(i, j) div 16) * MAP_TILE_HEIGHT;
				dst_rect1.x := i * MAP_TILE_WIDTH;
				dst_rect1.y := j * MAP_TILE_HEIGHT;
				SDL_RenderCopy(renderer, map.sprite_tile, @src_rect1, @dst_rect1);
			end;
			
	i := 0;
	while animated_tile[i].enabled do
		begin
			src_rect1.x := ((animated_tile[i].index mod 16) * MAP_TILE_WIDTH) + ((animated_tile[i].frame div 8) * MAP_TILE_WIDTH);
			src_rect1.y := (animated_tile[i].index div 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) mod 16;
			SDL_RenderCopy(renderer, map.sprite_tile, @src_rect1, @dst_rect1);
			inc(i);
		end;
end;

procedure DrawHud();
begin
	// 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 mod 100) div 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 mod 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 div 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 mod 100) div 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 mod 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 then
		begin
			// Pinta el valor x,y del jugador
			hud.num_src_rect.x := (player.dst_rect.x div 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);
			
			hud.num_src_rect.x := ((player.dst_rect.x mod 100) div 10) * hud.num_src_rect.w;
			hud.num_dst_rect.x := 5;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
			
			hud.num_src_rect.x := (player.dst_rect.x mod 10) * hud.num_src_rect.w;
			hud.num_dst_rect.x := 9;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
			
			hud.num_src_rect.x := (player.dst_rect.y div 100) * hud.num_src_rect.w;
			hud.num_dst_rect.x := 17;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
			
			hud.num_src_rect.x := ((player.dst_rect.y mod 100) div 10) * hud.num_src_rect.w;
			hud.num_dst_rect.x := 21;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
			
			hud.num_src_rect.x := (player.dst_rect.y mod 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) then
				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);
			
			hud.num_src_rect.x := (ReadMapTile((player.dst_rect.x + 3) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div 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);
			
			hud.num_src_rect.x := (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h) div 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);
			
			// Pinta el numero d'habitació
			hud.num_src_rect.x := (map.room div 100) * hud.num_src_rect.w;
			hud.num_dst_rect.y := 1;
			hud.num_dst_rect.x := 49;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
			
			hud.num_src_rect.x := ((map.room mod 100) div 10) * hud.num_src_rect.w;
			hud.num_dst_rect.x := 53;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
			
			hud.num_src_rect.x := (map.room mod 10) * hud.num_src_rect.w;
			hud.num_dst_rect.x := 57;
			DrawSprite(hud.sprite, hud.num_src_rect, hud.num_dst_rect);
		end;
end;

procedure CheckPlayerCollisionWithMap();
var
	tile_on_left_foot, tile_on_right_foot	: byte;		// [27/05/2016] [DOC]
	i_am_on_platform,  i_am_on_travesable	: boolean;	// [27/05/2016] [DOC]
begin
	// Si eix per baix, recalcula posició i canvi de pantalla
	if (player.dst_rect.y > GAME_WINDOW_HEIGHT) then
		begin
			// Coloquem al jugador dalt de tot
			player.dst_rect.y := 1;
			
			// Canvi de pantalla
			LoadRoom(map.room + 12);
		end;
	
	// Si eix per dalt, recalcula posició i canvi de pantalla
	if ((player.dst_rect.y + player.dst_rect.h - 1) < 0) then
		begin
			// Recoloca el personat
			player.dst_rect.y := GAME_WINDOW_HEIGHT - player.dst_rect.h;
			
			// Canvi de pantalla
			LoadRoom(map.room - 12);
		end;
		
	// Si eix per la vora, recalcula posició i canvi de pantalla
	if (player.dst_rect.x > GAME_WINDOW_WIDTH) then
		begin
			// Coloquem al jugador en la entrada de la nova pantalla
			player.dst_rect.x := 0;
			
			// Canvi de pantalla
			LoadRoom(map.room + 1);
		end;
				
	// Si eix per la vora, recalcula posició i canvi de pantalla
	if ((player.dst_rect.x + player.dst_rect.w - 1) < 0) then
		begin
			// El posem al borde dret
			player.dst_rect.x := GAME_WINDOW_WIDTH - player.dst_rect.w;
			
			// Canvi de pantalla
			LoadRoom(map.room - 1);
		end;
	
	// Mirem si colisionem cap avall i corregim
	//[27/05/2016] [DOC] [BEGIN]
	tile_on_left_foot  := ReadMapTile((player.dst_rect.x + 3) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT);
	tile_on_right_foot := ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT);
	
	i_am_on_platform   := (tile_on_left_foot = TILE_PLATFORM) 			 or (tile_on_right_foot = TILE_PLATFORM);
	i_am_on_travesable := (tile_on_left_foot = TILE_TRAVESABLE_PLATFORM) or (tile_on_right_foot = TILE_TRAVESABLE_PLATFORM);

	if ( (player.was_on_background) and (player.speed_y > 0) and ( i_am_on_platform or i_am_on_travesable ) ) then
		begin
			// Corregim la posicio
			player.dst_rect.y := player.dst_rect.y - ((player.dst_rect.y + player.dst_rect.h - 1) mod MAP_TILE_HEIGHT) - 1;
			
			// Ja podem saltar
			player.can_jump := TRUE;
		end;
		
	player.was_on_background := (tile_on_left_foot = TILE_BACKGROUND) and (tile_on_right_foot = TILE_BACKGROUND);
	//[27/05/2016] [DOC] [END]
		
	{if player.speed_y > 0 then
	if (ReadMapTile((player.dst_rect.x + 3) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT) = TILE_TRAVESABLE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT) = TILE_TRAVESABLE_PLATFORM) then
		begin
			// Corregim la posicio
			player.dst_rect.y := player.dst_rect.y - ((player.dst_rect.y + player.dst_rect.h - 1) mod MAP_TILE_HEIGHT) - 1;
			
			// Ja podem saltar
			player.can_jump := TRUE;
		end;
		
	if (ReadMapTile((player.dst_rect.x + 3) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT) = TILE_PLATFORM) then
		begin
			// Corregim la posicio
			player.dst_rect.y := player.dst_rect.y - ((player.dst_rect.y + player.dst_rect.h - 1) mod MAP_TILE_HEIGHT) - 1;
			
			// Ja podem saltar
			player.can_jump := TRUE;
		end;}
	
	// Mirem si colisionem cap amunt i corregim
	if (ReadMapTile((player.dst_rect.x + 3) div MAP_TILE_WIDTH, player.dst_rect.y div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 4) div MAP_TILE_WIDTH, player.dst_rect.y div MAP_TILE_HEIGHT) = TILE_PLATFORM) then
		// Corregim la posicio
		player.dst_rect.y := player.dst_rect.y + (MAP_TILE_HEIGHT - (player.dst_rect.y mod 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 div MAP_TILE_WIDTH, player.dst_rect.y div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile(player.dst_rect.x div MAP_TILE_WIDTH, (player.dst_rect.y + (player.dst_rect.h div 2)) div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile(player.dst_rect.x div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT) = TILE_PLATFORM) then
		player.dst_rect.x := player.dst_rect.x + (MAP_TILE_WIDTH - (player.dst_rect.x mod MAP_TILE_WIDTH));
	
	if (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 1) div MAP_TILE_WIDTH, player.dst_rect.y div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 1) div MAP_TILE_WIDTH, (player.dst_rect.y + (player.dst_rect.h div 2)) div MAP_TILE_HEIGHT) = TILE_PLATFORM)
	or (ReadMapTile((player.dst_rect.x + player.dst_rect.w - 1) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 1) div MAP_TILE_HEIGHT) = TILE_PLATFORM) then
		player.dst_rect.x := player.dst_rect.x - ((player.dst_rect.x + player.dst_rect.w) mod MAP_TILE_WIDTH);
		
	// Comprovar si toca alguna part del mapa de les que maten
	if (ReadMapTile((player.dst_rect.x + 8) div MAP_TILE_WIDTH, (player.dst_rect.y + player.dst_rect.h - 12) div MAP_TILE_HEIGHT) = TILE_KILLING_PLATFORM) then 
		if player.enabled then
			KillPlayer();
end;

{procedure CheckPlayerCollisionWithActors();
var
	i, collision:	byte;
	//collision_top, collision_bottom, collision_left, collision_right:	boolean;
begin
	for i:=0 to MAX_ACTORS - 1 do
		if actor[i].enabled then
			begin
				collision := NO_COLLISION;
				if ((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
				(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
					collision := LEFT_COLLISION;
				
				if((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
				(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
					collision := RIGHT_COLLISION;
					
				if ((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
				(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
					collision := LEFT_COLLISION;
				
				if ((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
				(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
					collision := RIGHT_COLLISION;
			
				if (collision <> NO_COLLISION) then
					case actor[i].kind of
						KIND_FLYING_ENEMY, KIND_WALKING_ENEMY, KIND_DROP_ENEMY, KIND_SPEED_ENEMY:
						begin
							if (player.enabled) then
								KillPlayer();	
						end;
						
						KIND_COIN:
						begin
							inc(player.coins);
							actor[i].enabled := FALSE;
							SetActor((actor[i].dst_rect.x div 16), (actor[i].dst_rect.y div 16), 0);
							Mix_PlayChannel(-1, player.sound_coin, 0);
						end;
						
						KIND_HEART:
						begin
							inc(player.lifes);
							actor[i].enabled := FALSE;
							SetActor((actor[i].dst_rect.x div 16), (actor[i].dst_rect.y div 16), 0);
							Mix_PlayChannel(-1, player.sound_coin, 0);
						end;
						
						KIND_KEY:
						begin
							player.key[0] := TRUE;;
							actor[i].enabled := FALSE;
							SetActor((actor[i].dst_rect.x div 16), (actor[i].dst_rect.y div 16), 0);
							Mix_PlayChannel(-1, player.sound_coin, 0);
						end;
						
						KIND_LOCK:
						begin
							// Si tenim clau
							if (player.key[0]) then
								begin
									actor[i].enabled := FALSE;
									SetActor((actor[i].dst_rect.x div MAP_TILE_WIDTH), (actor[i].dst_rect.y div MAP_TILE_HEIGHT), 0);
								end
							else
								begin
									if collision = LEFT_COLLISION then
										begin
											player.dst_rect.x := player.dst_rect.x + (MAP_TILE_WIDTH - (player.dst_rect.x mod MAP_TILE_WIDTH));
										end
									else
										begin
											player.dst_rect.x := player.dst_rect.x - ((player.dst_rect.x + player.dst_rect.w) mod MAP_TILE_WIDTH);
										end;
								end;
						end;
					end;
			end;
end;}

procedure CheckPlayerCollisionWithActors();
var
	i:	byte;
begin
	for i:=0 to MAX_ACTORS - 1 do
		if actor[i].enabled then
			case actor[i].kind of
				KIND_FLYING_ENEMY, KIND_WALKING_ENEMY, KIND_DROP_ENEMY, KIND_SPEED_ENEMY:
				begin
					if ((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
						if (player.enabled) then
							KillPlayer();	
				end;
				
				KIND_COIN:
				begin
					if ((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
						begin
							inc(player.coins);
							actor[i].enabled := FALSE;
							SetActor((actor[i].dst_rect.x div 16), (actor[i].dst_rect.y div 16), 0);
							Mix_PlayChannel(-1, player.sound_coin, 0);
						end;
				end;
				
				KIND_HEART:
				begin
					if ((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
						begin
							inc(player.lifes);
							actor[i].enabled := FALSE;
							SetActor((actor[i].dst_rect.x div 16), (actor[i].dst_rect.y div 16), 0);
							Mix_PlayChannel(-1, player.sound_coin, 0);
						end;
				end;
				
				KIND_KEY:
				begin
					if ((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h - ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w - ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION > player.dst_rect.x) and (actor[i].dst_rect.x + ENEMY_HITBOX_REDUCTION < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION > player.dst_rect.y) and (actor[i].dst_rect.y + ENEMY_HITBOX_REDUCTION < player.dst_rect.y + player.dst_rect.h)) then
						begin
							player.key[actor[i].id] := TRUE;;
							actor[i].enabled := FALSE;
							SetActor((actor[i].dst_rect.x div 16), (actor[i].dst_rect.y div 16), 0);
							Mix_PlayChannel(-1, player.sound_coin, 0);
						end;
				end;
				
				KIND_LOCK:
				// Les colisions amb aquest actor no tenen en compte el ENEMY_HITBOX_REDUCTION
				begin
					// 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) and (actor[i].dst_rect.x + actor[i].dst_rect.w < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x + actor[i].dst_rect.w > player.dst_rect.x) and (actor[i].dst_rect.x + actor[i].dst_rect.w < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y > player.dst_rect.y) and (actor[i].dst_rect.y < player.dst_rect.y + player.dst_rect.h)) then
						// Si tenim clau
						if (player.key[actor[i].id]) then
							begin
								actor[i].enabled := FALSE;
								SetActor((actor[i].dst_rect.x div MAP_TILE_WIDTH), (actor[i].dst_rect.y div MAP_TILE_HEIGHT), 0);
							end
						// Si no tenim clau
						else
							begin
								player.dst_rect.x := player.dst_rect.x + (MAP_TILE_WIDTH - (player.dst_rect.x mod MAP_TILE_WIDTH));
							end;
					
					// El jugador colisiona amb el actor per la dreta del jugador
					if ((actor[i].dst_rect.x > player.dst_rect.x) and (actor[i].dst_rect.x < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y + actor[i].dst_rect.h > player.dst_rect.y) and (actor[i].dst_rect.y + actor[i].dst_rect.h < player.dst_rect.y + player.dst_rect.h))
					or
					((actor[i].dst_rect.x > player.dst_rect.x) and (actor[i].dst_rect.x < player.dst_rect.x + player.dst_rect.w) and
					(actor[i].dst_rect.y > player.dst_rect.y) and (actor[i].dst_rect.y < player.dst_rect.y + player.dst_rect.h)) then
						// Si tenim clau
						if (player.key[actor[i].id]) then
							begin
								actor[i].enabled := FALSE;
								SetActor((actor[i].dst_rect.x div MAP_TILE_WIDTH), (actor[i].dst_rect.y div MAP_TILE_HEIGHT), 0);
							end
						// Si no tenim clau
						else
							begin
								player.dst_rect.x := player.dst_rect.x - ((player.dst_rect.x + player.dst_rect.w) mod MAP_TILE_WIDTH);
							end;
				end;
			end;
end;

procedure SetProgSection(section:byte);
begin
	case section of
		SECTION_MENU:
		begin
			prog.section := SECTION_MENU;
			IniMenu();
			EndGame();
		end;
		
		SECTION_GAME:
		begin
			prog.section := SECTION_GAME;
			IniGame(ZONE_VOLCANO);
			EndMenu;
		end;
		
		SECTION_QUIT:
		begin
			prog.section := SECTION_QUIT;
			EndGame;
			EndMenu;
		end;
	end;
end;

procedure IniProgram();
begin
	prog.music_enabled := TRUE;
	prog.filter := TRUE;
	SetProgSection(SECTION_MENU);
	prog.debug := FALSE;
	
	if (prog.music_enabled) then
		Mix_VolumeMusic(100)
	else
		Mix_VolumeMusic(0);
		
	prog.sprite := OpenPicture(FILE_FILTER);
	
	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;
end;

procedure EndProgram();
begin
	ClosePicture(prog.sprite);
	EndGame();
	EndMenu();
end;

begin
	// Inicialitzar SDL en general i el video en particular
	fullscreen := false;
	SDL_Init(SDL_INIT_EVERYTHING);
	window := SDL_CreateWindow(WINDOW_TITLE + BUILD, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
	renderer := SDL_CreateRenderer(window, -1, 0);
	SDL_RenderSetLogicalSize(renderer, 320, 240);

	// Inicialitzar SDL_Image (càrrega de PNGs)
	IMG_Init(IMG_INIT_PNG);

	// Inicialitzar audio
	Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024);
	Mix_AllocateChannels(8);
	
	// Inicialitzar el programa
	IniProgram();
	
	// Establir el color d'esborrat
	SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

	// Inicialitza variables generals
	quit := false;
	delta_time := SDL_GetTicks();

	// Bucle de programa
	while not quit do
	begin
		case prog.section of
		SECTION_GAME:
		begin
			// Inicialitza habitació
			LoadRoom(STARTING_ROOM);
			
			// Conecta la musica
			Mix_PlayMusic(game.music, -1);
			
			// Bucle de joc
			while game.enabled do
			begin
				while SDL_PollEvent(@e) > 0 do
					begin
						// Si arriva el event de tancar la aplicació, eixim del bucle
						if (e.type_ = SDL_QUITEV) then
							begin
								quit := true;
								SetProgSection(SECTION_MENU);
								break;
							end
						else
							if ((e.type_ = SDL_KEYDOWN) and (e.key._repeat = 0)) then
								case e.key.keysym.scancode of
									SDL_SCANCODE_ESCAPE:
									begin
										SetProgSection(SECTION_MENU);
									end;

									SDL_SCANCODE_F:
									begin
										if ( fullscreen ) then
											begin
												SDL_SetWindowFullscreen(window, 0);
												SDL_ShowCursor(1);
												fullscreen := false;
											end
										else
											begin
												SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
												SDL_ShowCursor(0);
												fullscreen := true;
											end;
									end;

									SDL_SCANCODE_W:
									begin
										LoadRoom(map.room - 12);
									end;
									
									SDL_SCANCODE_A:
									begin
										LoadRoom(map.room - 1);
									end;
									
									SDL_SCANCODE_S:
									begin
										LoadRoom(map.room + 12);
									end;
									
									SDL_SCANCODE_D:
									begin
										LoadRoom(map.room + 1);
									end;
									
									SDL_SCANCODE_G:
									begin
										player.lifes := 255;
									end;
									
									SDL_SCANCODE_M:
									begin
										prog.music_enabled := not(prog.music_enabled);
										if (prog.music_enabled) then
											Mix_VolumeMusic(100)
										else
											Mix_VolumeMusic(0);
									end;
														
									SDL_SCANCODE_T:
									begin
										IniPlayer();
										LoadRoom(TEST_ROOM);
									end;
									
									SDL_SCANCODE_F1:
									begin
										prog.debug := not(prog.debug);
									end;
									
									SDL_SCANCODE_F2:
									begin
										prog.filter := not(prog.filter);
									end;
								end;
					end;

				if ((SDL_GetTicks() - delta_time) > GAME_SPEED) then
					begin
						// Agafar el array de tecles
						keys := SDL_GetKeyboardState(nil);
						
						// Mirem si esta apretant el botó de saltar. Per tal d'evitar repeticions en aquest boto
						if (keys[SDL_SCANCODE_UP] = 0) then
							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 not(player.enabled) then
							if (player.cooldown > 0) then
								begin
									dec(player.cooldown);
									Animate(player.animation[player.active_animation], player.src_rect);
								end
							else
								// Ha acabat el temps d'estar mort. Revivim al jugador
								begin
									player.enabled := TRUE;
									
									// Coloquem al jugador en el sentit que tenia quan va entrar a la habitació
									if (player.respawn_direction = LEFT) then
										begin
											SetPlayerAnimation(PLAYER_ANIMATION_STANDING_LEFT);
											player.direction := LEFT;
										end;
									if (player.respawn_direction = RIGHT) then
										begin
											SetPlayerAnimation(PLAYER_ANIMATION_STANDING_RIGHT);
											player.direction := RIGHT;
										end;
									
									// Coloquem al jugador en les coordenades per on va entrar
									player.dst_rect.x := 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) then
										// Descontem una vida
										dec(player.lifes)
									else
										// Si no li queden vides, eixim al menu
										SetProgSection(SECTION_MENU);
								end;
						
						// Comprovem les tecles que ens interesen i actuem en consequència
						if (keys[SDL_SCANCODE_RIGHT] = 1) and (player.enabled) then
							MovePlayer(RIGHT);
						if (keys[SDL_SCANCODE_LEFT] = 1) and (keys[SDL_SCANCODE_RIGHT] = 0) and (player.enabled) then
							MovePlayer(LEFT);
						if (keys[SDL_SCANCODE_UP] = 1) and (player.enabled) and not(player.jump_pressed_before) then
							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) and (keys[SDL_SCANCODE_LEFT] = 0) and (player.enabled)) then
							begin
								player.speed_x := 0;
								
								// Estem quets
								player.standing := TRUE;
								
								// Posem la animació d'estar quet si no estem saltant
								//if (player.speed_y = 0) then
								if (player.can_jump) then
									begin
										if (player.direction = LEFT) then
											SetPlayerAnimation(PLAYER_ANIMATION_STANDING_LEFT)
										else
											if (player.direction = RIGHT) then
												SetPlayerAnimation(PLAYER_ANIMATION_STANDING_RIGHT);
										Animate(player.animation[player.active_animation], player.src_rect);
									end;
							end;
						
						// Moure els actors
						MoveActors();
						
						// Apliquem la gravetat
						if (player.enabled) then ApplyGravity();
						
						// Comprovar colisions amb els actors
						if (player.enabled) then 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(map);
						
						// Pintem el jugador
						DrawSprite(player.sprite, player.src_rect, player.dst_rect);
						
						// Pintem els actors
						for i:=0 to MAX_ACTORS - 1 do
							if (actor[i].enabled) then
								DrawSprite(map.sprite_actor, actor[i].src_rect, actor[i].dst_rect);
						
						// Pintem el marcador
						DrawHud();	
						
						// Posem el filtro de pantalla
						if prog.filter then
							begin
								SDL_RenderSetLogicalSize(renderer, 640, 480);
								DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
							end;
						
						// Mostrem la pantalla
						SDL_RenderPresent(renderer);
						
						delta_time := SDL_GetTicks();
					end;
			end;
		end;
		
		SECTION_MENU:
		begin
			// Establir el color d'esborrat
			SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
			
			// Apaga la musica
			Mix_HaltMusic();
			
			while menu.enabled do
			begin
				// Bucle del menu
				while SDL_PollEvent(@e) > 0 do
					begin
						// Si arriva el event de tancar la aplicació, eixim del bucle
						if (e.type_ = SDL_QUITEV) then
							begin
								quit := true;
								menu.enabled := FALSE;
								break;
							end
						else
							if ((e.type_ = SDL_KEYDOWN) and (e.key._repeat = 0)) then
								case e.key.keysym.scancode of
									SDL_SCANCODE_ESCAPE:
									begin
										quit := true;
										SetProgSection(SECTION_QUIT);
										break;
									end;
									
									// (Des)Activa el mode de pantalla completa
									SDL_SCANCODE_F:
									begin
										if ( fullscreen ) then
											begin
												SDL_SetWindowFullscreen(window, 0);
												SDL_ShowCursor(1);
												fullscreen := false;
											end
										else
											begin
												SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
												SDL_ShowCursor(0);
												fullscreen := true;
											end;
									end;
									
									// (Des)Activa la musica
									SDL_SCANCODE_M:
									begin
										prog.music_enabled := not(prog.music_enabled);
										if (prog.music_enabled) then
											Mix_VolumeMusic(100)
										else
											Mix_VolumeMusic(0);
									end;
									
									// (Des)Activa les scanlines
									SDL_SCANCODE_F2:
									begin
										prog.filter := not(prog.filter);
									end;
									
									// Inicia el joc
									SDL_SCANCODE_RETURN:
									begin
										if (menu.timer > 99) then
											begin
												menu.timer := 99;
												Mix_HaltMusic();
												Mix_HaltChannel(-1);
												Mix_PlayChannel(-1, menu.sound_start, 0);
												menu.frame := 0;
											end;
									end;
								end;
					end;

				if ((SDL_GetTicks() - delta_time) > GAME_SPEED) then
					begin
						case menu.section of
						{MENU_SECTION_MAIN:
							begin
								if menu.timer > 100 then
									// Menu normal
									begin
										menu.frame := (menu.frame + 1) mod 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 := 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 div 4) then
											Mix_PlayChannel(-1, menu.sound_logo, 0);
										if menu.frame = (300 div 4) then
											// Conecta la musica
											Mix_PlayMusic(menu.music, -1);
										
										if menu.frame > (300 div 4) then
										begin
											// Pintem el text: PRESS RETURN TO START
											if ((menu.frame mod 64) < 32) then
												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);
										end;
									end
								else
									// Menu havent apretat START/RETURN
									begin
										dec(menu.timer);
										menu.frame := (menu.frame + 1) mod 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 mod 8) < 4) then
											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 then
											begin
												//prog.section := SECTION_GAME;
												//menu.enabled := FALSE;
												//game.enabled := TRUE;
												//menu.section := MENU_SECTION_ANIMATION;
												//menu.timer := 100
											end;
									end;
								
								// Posem el filtro de pantalla
								if prog.filter then
									begin
										SDL_RenderSetLogicalSize(renderer, 640, 480);
										DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
									end;
									
								// Mostrem la pantalla
								SDL_RenderPresent(renderer);

								delta_time := SDL_GetTicks();
							end;}
						
							MENU_SECTION_ANIMATION:
								begin
									// No hem pulsat el botó d'start
									if menu.timer > 100 then
										// Animació inicial
										if not(menu.animation[0].loops) then
											begin
												// 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 then
													begin
														SDL_RenderSetLogicalSize(renderer, 640, 480);
														DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
													end;
													
												// Mostrem la pantalla
												SDL_RenderPresent(renderer);
												
												delta_time := SDL_GetTicks();
											end
										else
											// Animació segona en loop
											begin
												if Mix_PlayingMusic() = 0 then
													Mix_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 mod 64) < 32) then
													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 then
													begin
														SDL_RenderSetLogicalSize(renderer, 640, 480);
														DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
													end;
													
												// Mostrem la pantalla
												SDL_RenderPresent(renderer);
												
												delta_time := SDL_GetTicks();
											end
									else
										// Hem pulsat el botó d'start
										begin
											Mix_HaltMusic();
											
											// 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 mod 8) < 4) then
												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 then
												begin
													SDL_RenderSetLogicalSize(renderer, 640, 480);
													DrawSprite(prog.sprite, prog.src_rect, prog.dst_rect);
												end;
												
											// Mostrem la pantalla
											SDL_RenderPresent(renderer);
											
											delta_time := SDL_GetTicks();
											
											dec(menu.timer);
											if menu.timer = 0 then
												begin
													SetProgSection(SECTION_GAME);
													menu.timer := 200;
												end;
										end;
								end;
						end;
					end;
				end;
			end;
		end;
    end;

	// Finalitzar la música, els samples i el audio
	CloseSound(player.sound_jump);
	CloseSound(player.sound_death);
	CloseSound(player.sound_coin);
	CloseSound(menu.sound_logo);
	CloseSound(menu.sound_start);
	CloseSound(game.sound_drop_enemy);
	CloseSound(game.sound_drop_splat);
	
	Mix_HaltMusic();

	CloseMusic(game.music);
	CloseMusic(menu.music);

	Mix_CloseAudio();
	
	EndProgram();

	// Finalitzar SDL_Image
	IMG_Quit();
	
	// 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);
	
	// Destruir la finestra
	SDL_DestroyWindow(window);
	
	// Finalitzar SDL
	SDL_Quit();
end.
