#ifndef _H_LEVEL
#define _H_LEVEL

#include "Bitmap.h"
#include "Entity.h"

#define LEVEL_SIZE 64

typedef unsigned char luxel_t;
#define LEVEL_LIGHTMAP_SCALE 8 /* Number of luxels per tile width */
#define LEVEL_LIGHTMAP_SIZE (LEVEL_SIZE * LEVEL_LIGHTMAP_SCALE)

#define OUTOFBOUNDS(x, y) ((x) < 0 || (x) >= LEVEL_SIZE || (y) < 0 || (y) >= LEVEL_SIZE)

#define LEVEL_HASGRASS		(1 << 0)
#define LEVEL_HASLADDERUP	(1 << 1)
#define LEVEL_HASLADDERDOWN	(1 << 2)
#define LEVEL_NOENTRANCE	(1 << 3)

enum TileType
{
	TILE_GROUND = '.',
	TILE_FLOOR = '_',
	TILE_STONE = '%',
	TILE_BRICK = '#',
	TILE_WATER = 'w',
	TILE_WOODPATH = '=',
	TILE_DOOR_CLOSED = 'D',
	TILE_DOOR_OPEN = 'd',
	TILE_LADDER_DOWN = 'S',
	TILE_LADDER_UP = 'A',
	TILE_ICE = '~',
	TILE_HURT = 'x',
	TILE_LAVA = 'X',
	TILE_OUTOFBOUNDS = '|'
};

extern struct _LevelData
{
	char *tilemap;
	char *vismap; /* Fog of war */
	luxel_t *lightmap;
	luxel_t *lightoverlay;
	/* The position of the ladder from the level above */
	int enterX, enterY;
	/* The position of the ladder to the level below */
	int exitX, exitY;
	int flags;
	char wallHeight; // No ceiling on level if less than 0
	unsigned char tileset;
	unsigned char ambientBrightness; // Value from 0 to 255, where 0 is pitch black and 255 is fullbright.
	unsigned char fogDepth; // Fog is thicker the higher the value is, 0 for no fog.
	bmcol_t fogColour;
	Obj_t *boss;
	char bossName[32];
	char songName[32];
	char enterName[64];
	Bmp_t *skybox;
	int bossColour;
	float		ambientParticleSpeed;
	uint32_t	ambientParticleColour;
} Level;

/* Allocates memory for buffers used by the global level variable */
void Lvl_Setup(void);
/* Resets all values in the level structure. This function will not allocate or de-allocate memory. */
void Lvl_Reset(void);
/* Initialize the level for a given depth, either by loading the approprivate save file or generating a new level */
void Lvl_LoadOrGenerate(int depth);
/* Frees memory allocated by Lvl_Setup() */
void Lvl_Cleanup(void);

struct RayHitResult
{
	float distance;
	/* X and Y position of the hit tile */
	int xt, yt;
	/* hitside 0 = wall normal is x axis*/
	/* hitside 1 = wall normal is y axis*/
	int hitSide;
};
struct RayHitResult Lvl_Raycast(float x, float y, float xdir, float ydir, bool revealMap);

int Lvl_IsWall(int x, int y);
int Lvl_IsDoor(int x, int y);
int Lvl_HasLineOfSight(float xsrc, float ysrc, float xdst, float ydst);

luxel_t Lvl_GetLuxel(int x, int y);
int Lvl_GetWallTex(int x, int y);
int Lvl_GetFloorTex(int x, int y);
int Lvl_GetCeilingTex(int x, int y);

void Lvl_FindLadders(void);

void Lvl_ComputeLightmap(void);
void Lvl_ComputeLightOverlay(void);

#endif
