#ifdef PRECOMPILEDHEADERS
	#include "TileEngine All.h"
#else
	#include "tiledef.h"
	#include "worlddef.h"
	#include "wcheck.h"
	#include "debug.h"
	#include "worldman.h"
	#include "edit_sys.h"
	#include "pathai.h"
	#include "tile surface.h"
	#include "Tactical Save.h"
#endif

//#include "editscreen.h"


// GLobals
TILE_ELEMENT		gTileDatabase[ NUMBEROFTILES ];
UINT16					gTileDatabaseSize;
UINT16					gusNumAnimatedTiles = 0;
UINT16					gusAnimatedTiles[ MAX_ANIMATED_TILES ];



UINT16						gTileTypeStartIndex[ NUMBEROFTILETYPES ];

UINT8 gubEncryptionArray2[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ] =
{
	{
	81,168,102,49,61,70,172,
	127,7,148,115,179,10,117,
	253,35,30,218,76,63,116,
	210,241,65,169,157,4,9,
	29,205,160,111,41,213,193,
	190,86,19,207,133,25,190,
	187,131,66,196,253,227,163
	},

	{
	236,81,128,26,96,137,92,
	120,243,71,33,141,55,2,
	185,185,187,33,230,72,146,
	143,226,21,110,155,226,150,
	111,124,165,242,4,76,201,
	34,223,227,29,202,119,86,
	172,219,8,121,183,148,142
	},

	{
	73,81,249,189,120,220,96,
	79,28,37,30,199,170,56,
	1,10,70,215,151,190,146,
	156,233,11,251,146,195,134,
	188,140,23,233,137,204,150,
	116,36,97,40,119,204,194,
	55,9,193,18,143,76,209
	},

	{
	143,200,80,50,154,231,247,
	140,225,72,226,136,2,99,
	209,182,82,146,128,49,3,
	98,101,196,95,136,85,3,
	81,37,131,9,251,79,209,
	101,128,157,238,229,205,178,
	49,161,141,101,175,48,2
	},

	{
	171,145,70,2,204,252,166,
	194,2,182,182,189,17,205,
	141,80,12,104,215,96,174,
	11,106,181,150,113,213,71,
	209,89,219,35,229,63,18,
	64,237,140,153,224,215,31,
	48,198,108,180,139,233,39
	},

	{
	31,60,240,131,203,6,32,
	206,137,249,244,36,8,39,
	38,142,11,77,76,18,200,
	76,210,138,106,198,130,22,
	37,178,76,18,233,77,149,
	77,28,47,186,126,72,234,
	254,158,97,10,162,58,93
	},

	{
	181,91,80,208,248,218,224,
	90,219,176,181,120,63,35,
	132,167,206,85,6,76,223,
	90,15,100,142,121,79,111,
	255,88,196,134,19,72,133,
	40,95,98,232,153,217,182,
	186,109,241,66,128,26,140
	},

	{
	225,112,22,157,253,52,123,
	209,31,7,165,18,48,83,
	190,53,154,87,188,199,251,
	248,185,48,164,93,44,22,
	165,77,239,88,148,21,155,
	115,203,231,20,170,83,100,
	222,204,57,83,39,241,126
	},

	{
	51,228,1,96,176,54,89,
	49,157,66,125,113,124,187,
	15,110,70,101,246,16,108,
	156,20,32,200,96,70,170,
	120,198,42,199,79,93,100,
	115,246,113,213,187,66,169,
	129,241,230,251,145,23,29
	},

	{
	101,67,67,78,108,22,58,
	97,212,30,230,190,142,195,
	243,169,75,210,61,248,180,
	47,75,218,191,5,154,172,
	19,204,224,123,244,251,1,
	94,192,187,249,33,79,120,
	115,109,88,173,40,7,61
	},

	{
	178,239,46,52,245,141,192,
	77,114,7,54,78,179,195,
	12,213,79,16,184,192,27,
	100,195,74,5,1,15,226,
	223,50,245,39,244,230,85,
	8,196,217,18,128,187,251,
	52,225,65,96,62,49,239
	},

	{
	94,190,122,81,36,204,171,
	249,104,120,214,89,133,203,
	103,19,163,117,53,59,48,
	182,240,91,101,160,234,121,
	1,78,151,26,3,28,228,
	130,138,137,188,21,167,198,
	197,34,63,165,195,11,206
	},

	{
	220,164,4,55,94,159,83,
	86,186,109,101,150,60,4,
	146,58,195,221,221,148,11,
	50,155,232,95,39,71,37,
	106,104,102,59,34,41,206,
	61,129,242,45,11,12,85,
	27,184,210,214,165,106,238
	},

	{
	44,151,227,47,39,93,122,
	237,91,225,164,198,235,53,
	226,36,124,86,57,94,185,
	251,231,101,120,178,168,162,
	218,38,34,33,126,235,196,
	151,30,175,212,103,170,17,
	208,48,75,16,231,10,66
	},

	{
	90,201,253,44,89,120,222,
	145,82,80,6,63,114,22,
	37,106,33,40,177,4,112,
	152,9,70,250,103,229,235,
	22,147,65,5,164,55,48,
	233,103,112,216,69,34,63,
	31,159,108,38,14,111,132
	},

	{
	170,177,43,7,140,86,71,
	207,205,235,155,239,88,129,
	53,6,111,139,249,208,172,
	252,34,88,175,213,251,129,
	86,54,242,107,142,144,79,
	96,161,29,171,196,16,17,
	143,205,207,201,47,88,10
	},

	{
	112,203,199,48,59,153,46,
	130,221,189,166,213,63,67,
	50,190,21,148,242,238,113,
	94,28,228,234,100,103,187,
	95,53,124,69,6,55,6,
	39,204,11,231,64,176,183,
	86,248,21,152,62,205,200
	},

	{
	133,189,180,176,46,27,167,
	213,33,253,7,209,112,92,
	8,60,122,206,229,50,184,
	207,25,142,34,149,64,234,
	16,252,247,255,22,70,90,
	126,212,16,93,248,50,89,
	194,248,244,230,224,203,62
	},

	{
	234,231,52,206,57,230,130,
	158,240,79,58,175,226,31,
	213,160,154,113,199,241,84,
	178,66,108,201,41,240,188,
	24,9,50,145,172,208,226,
	100,127,42,93,55,123,245,
	197,102,110,206,48,234,81
	},

	{
	176,193,13,70,253,101,15,
	39,156,34,168,239,92,185,
	235,239,109,151,115,6,12,
	184,92,210,40,152,12,36,
	57,183,30,136,247,232,152,
	77,59,225,190,208,165,59,
	133,118,100,111,45,20,177
	},

	{
	242,224,56,94,247,232,26,
	5,5,92,145,57,226,205,
	229,79,2,235,214,16,252,
	135,176,247,51,4,190,78,
	45,155,6,184,220,121,136,
	151,66,29,253,210,166,255,
	75,82,234,246,152,230,26
	},

	{
	71,92,199,196,224,54,108,
	71,191,224,240,145,231,54,
	198,135,241,115,219,139,162,
	178,253,95,131,237,175,212,
	251,85,23,132,211,92,89,
	14,166,88,5,254,58,254,
	204,5,41,160,72,105,230
	},

	{
	122,240,140,138,243,30,90,
	95,32,36,108,168,91,94,
	223,161,93,96,118,32,153,
	235,41,222,65,8,181,221,
	196,207,70,218,41,74,198,
	79,6,240,9,240,142,41,
	69,48,113,102,15,168,239
	},

	{
	33,100,248,1,115,220,254,
	216,113,156,238,175,27,36,
	61,20,255,131,209,181,91,
	40,126,238,227,186,46,228,
	253,64,201,169,138,5,71,
	30,20,119,212,255,127,121,
	170,240,13,84,96,212,210
	},

	{
	213,91,87,107,184,54,252,
	30,240,165,139,29,230,205,
	42,49,78,136,10,113,160,
	132,246,82,211,200,164,178,
	112,128,15,43,150,157,197,
	88,7,48,126,75,210,2,
	196,228,191,100,25,80,254
	},

	{
	161,100,85,71,23,7,176,
	250,104,108,62,88,195,110,
	27,102,177,102,127,163,105,
	65,133,21,24,117,155,208,
	39,37,206,154,225,85,176,
	161,128,129,8,6,18,114,
	12,53,53,165,90,177,26
	},

	{
	36,101,106,199,26,144,50,
	33,13,177,101,149,6,56,
	112,251,141,157,46,152,191,
	112,214,180,104,160,119,202,
	112,75,167,190,116,185,126,
	27,229,214,110,194,128,191,
	19,24,123,193,148,15,69
	},

	{
	94,179,36,34,168,18,167,
	136,168,214,94,144,245,66,
	241,83,82,74,25,138,106,
	213,7,78,133,181,254,75,
	73,230,160,60,93,65,204,
	19,24,42,169,150,246,86,
	182,211,11,68,108,69,44
	},

	{
	127,97,243,9,60,97,125,
	234,114,130,69,83,11,157,
	186,44,46,37,4,205,85,
	226,218,134,60,127,11,227,
	55,80,85,109,26,120,25,
	19,60,173,155,255,182,196,
	64,12,112,91,145,131,23
	},

	{
	166,108,127,147,227,40,125,
	27,76,18,129,108,39,24,
	100,92,205,245,147,59,47,
	190,251,54,204,28,72,76,
	151,24,71,228,181,206,140,
	172,161,216,38,201,154,203,
	141,252,226,169,135,208,183
	},

	{
	143,63,98,145,133,62,237,
	139,191,134,154,119,47,128,
	196,154,179,252,48,125,206,
	245,106,207,37,87,203,218,
	175,115,73,116,243,111,167,
	231,22,81,34,216,26,234,
	36,136,62,97,46,137,172
	},

	{
	125,118,61,116,135,101,54,
	15,215,129,210,84,238,226,
	43,56,40,197,174,30,226,
	95,117,34,65,115,192,53,
	67,222,155,83,103,157,18,
	188,158,107,3,133,177,144,
	242,76,231,253,233,120,19
	},

	{
	65,199,211,202,123,9,216,
	255,223,125,141,168,222,211,
	71,184,143,146,32,40,117,
	82,140,45,50,203,212,115,
	70,166,219,132,100,127,245,
	11,146,38,66,68,135,130,
	71,59,123,29,51,25,249
	},

	{
	190,161,56,194,42,46,58,
	104,89,177,209,173,64,141,
	117,68,136,202,201,9,67,
	112,209,78,255,233,204,77,
	72,199,213,85,252,204,10,
	221,117,125,115,252,250,46,
	101,111,125,194,139,186,255
	},

	{
	31,86,139,193,121,21,227,
	136,133,87,49,18,190,230,
	224,29,177,1,149,9,151,
	24,129,123,31,191,15,12,
	186,16,109,103,75,43,16,
	233,124,37,188,28,178,253,
	78,27,215,234,165,87,234
	},

	{
	170,4,161,157,18,78,11,
	223,148,86,130,184,244,199,
	171,43,229,209,235,160,189,
	23,30,145,9,19,238,221,
	41,113,74,156,184,137,226,
	186,241,135,67,86,193,87,
	95,11,215,251,31,39,80
	},

	{
	85,223,21,67,248,93,201,
	234,55,255,161,143,221,252,
	110,10,206,90,36,240,21,
	39,237,78,109,10,6,248,
	7,125,44,88,104,198,17,
	195,47,15,140,61,184,167,
	251,182,72,224,147,159,196
	},

	{
	123,19,239,168,30,154,104,
	60,207,7,69,172,234,176,
	23,31,137,211,242,79,208,
	145,194,222,40,205,220,218,
	202,197,167,163,162,203,119,
	188,250,215,100,172,230,115,
	79,119,241,177,204,213,247
	},

	{
	164,47,183,166,25,101,55,
	173,255,232,132,251,73,117,
	235,22,152,184,146,245,171,
	192,242,110,184,81,188,135,
	183,224,50,201,210,124,141,
	254,235,54,153,73,133,105,
	251,27,228,131,103,255,205
	},

	{
	141,53,177,160,37,136,109,
	76,46,150,5,207,226,32,
	160,180,136,191,175,88,111,
	36,245,86,149,192,56,237,
	119,37,117,196,117,115,54,
	203,93,49,208,170,113,233,
	46,143,140,211,5,170,166
	},

	{
	2,245,56,116,61,150,114,
	76,28,201,61,29,126,115,
	226,153,233,246,200,95,246,
	112,88,77,97,48,22,186,
	203,102,27,213,211,119,235,
	204,147,244,229,21,29,175,
	52,103,21,222,146,203,247
	},

	{
	203,187,75,44,10,228,157,
	113,156,9,120,202,29,117,
	184,122,64,90,44,31,194,
	191,30,155,50,190,115,208,
	130,69,132,201,246,81,100,
	108,67,226,228,85,112,150,
	243,222,107,49,158,2,199
	},

	{
	243,107,29,155,25,62,54,
	254,77,132,226,20,121,227,
	78,33,189,27,153,172,240,
	78,17,13,117,133,92,119,
	205,123,66,233,177,141,20,
	2,21,244,85,47,218,7,
	194,47,175,180,65,92,188
	},

	{
	3,223,186,179,171,112,64,
	226,172,223,83,208,235,215,
	235,20,187,212,96,218,104,
	41,66,233,141,50,89,115,
	102,35,34,147,219,175,203,
	216,121,7,60,166,18,77,
	246,202,53,41,124,33,72
	},

	{
	115,8,155,105,168,30,132,
	213,57,253,89,18,62,83,
	13,138,197,40,21,218,47,
	156,13,133,209,66,82,67,
	99,176,107,172,80,52,146,
	108,148,19,61,193,41,114,
	250,121,164,57,125,29,35
	},

	{
	252,37,152,15,100,236,254,
	226,253,7,172,123,6,10,
	139,17,7,254,146,114,216,
	45,95,154,241,252,4,47,
	134,193,201,19,97,207,39,
	144,254,165,157,60,218,144,
	173,48,97,157,173,165,139
	},

	{
	43,160,148,141,246,225,109,
	162,9,196,127,84,62,238,
	41,82,224,161,103,65,28,
	169,227,113,157,43,7,17,
	78,6,67,179,102,7,16,
	186,197,164,203,143,211,114,
	255,34,222,17,63,184,47
	},

	{
	202,17,101,190,148,37,65,
	227,178,78,200,202,174,105,
	90,13,220,198,78,74,44,
	37,172,23,111,225,219,23,
	223,119,96,149,12,206,14,
	131,243,148,179,37,120,26,
	168,77,232,223,65,125,224
	},

	{
	95,160,190,37,50,215,151,
	196,31,209,227,48,62,1,
	249,123,173,73,232,137,16,
	25,39,88,73,51,149,31,
	178,19,34,120,74,112,230,
	97,243,213,31,34,121,189,
	200,255,68,57,75,208,129
	},

	{
	135,244,60,186,169,184,217,
	128,88,234,225,59,98,108,
	180,189,228,11,222,179,81,
	129,225,122,192,210,117,133,
	142,124,112,228,166,55,29,
	3,133,178,40,47,107,31,
	237,22,170,212,75,186,142
	},

	{
	254,191,1,222,153,4,115,
	100,149,222,68,112,139,102,
	61,231,195,98,156,181,242,
	24,137,44,136,34,43,76,
	219,155,8,100,28,81,181,
	252,75,50,126,154,46,177,
	11,53,126,99,180,248,57
	},

	{
	109,132,42,96,40,141,189,
	8,138,168,147,13,172,54,
	196,69,7,241,14,128,187,
	124,187,63,140,172,27,97,
	195,63,235,191,196,254,187,
	234,123,1,174,6,88,6,
	177,247,45,156,120,226,125
	},

	{
	30,95,46,155,25,137,245,
	52,68,72,74,137,152,60,
	3,26,152,42,137,223,113,
	244,114,229,1,192,53,115,
	90,174,232,119,234,38,77,
	114,195,46,6,151,52,203,
	85,96,69,205,58,68,39
	},

	{
	30,59,201,53,236,197,180,
	160,196,103,128,88,254,209,
	225,82,124,227,135,183,59,
	172,203,39,154,168,155,144,
	235,35,68,198,41,8,87,
	105,92,255,110,51,167,55,
	248,69,103,157,208,146,105
	},

	{
	249,205,245,168,172,15,16,
	148,112,53,141,74,5,64,
	218,194,253,75,243,113,168,
	228,80,59,85,44,153,81,
	216,126,55,215,165,220,72,
	217,83,199,41,128,227,208,
	24,3,173,137,18,75,53
	},

	{
	21,130,191,209,19,213,58,
	123,18,147,139,147,81,14,
	156,255,245,64,150,115,131,
	244,12,61,185,211,155,114,
	151,96,11,203,200,138,71,
	17,26,234,71,106,73,60,
	76,106,210,50,115,45,2
	},

	{
	55,17,107,248,62,204,196,
	224,45,253,50,10,2,51,
	233,34,73,107,137,68,253,
	235,235,24,99,52,125,184,
	3,3,88,146,80,226,29,
	5,25,66,196,226,87,125,
	83,169,124,218,190,135,197
	},
};

#if 0
// These values coorespond to TerrainTypeDefines order
UINT8		gTileTypeMovementCost[ NUM_TERRAIN_TYPES ] =
{
	TRAVELCOST_FLAT,						// NO_TERRAIN
	TRAVELCOST_FLAT,						// FLAT GROUND
	TRAVELCOST_FLATFLOOR,				// FLAT FLOOR
	TRAVELCOST_PAVEDROAD,				// PAVED ROAD
	TRAVELCOST_DIRTROAD,				// DIRT ROAD
	TRAVELCOST_GRASS,						// LOW_GRASS
	TRAVELCOST_THICK,						// HIGH GRASS
	TRAVELCOST_TRAINTRACKS,			// TRAIN TRACKS
	TRAVELCOST_SHORE,						// LOW WATER
	TRAVELCOST_KNEEDEEP,						// MED WATER
	TRAVELCOST_DEEPWATER,						// DEEP WATER
};
#else
// These values coorespond to TerrainTypeDefines order
UINT8		gTileTypeMovementCost[ NUM_TERRAIN_TYPES ] =
{
	TRAVELCOST_FLAT,						// NO_TERRAIN
	TRAVELCOST_FLAT,						// FLAT GROUND
	TRAVELCOST_FLATFLOOR,				// FLAT FLOOR
	TRAVELCOST_PAVEDROAD,				// PAVED ROAD
	TRAVELCOST_DIRTROAD,				// DIRT ROAD
	TRAVELCOST_FLAT,						// LOW_GRASS
	TRAVELCOST_FLAT,						// HIGH GRASS
	TRAVELCOST_TRAINTRACKS,			// TRAIN TRACKS
	TRAVELCOST_SHORE,						// LOW WATER
	TRAVELCOST_SHORE,						// MED WATER
	TRAVELCOST_SHORE,						// DEEP WATER
};
#endif

ADDITIONAL_TILE_PROPERTIES_VALUES zAdditionalTileProperties;

void CreateTileDatabase( INT32 iTilesetID )
{
	UINT32					cnt1, cnt2;
	UINT8 ubLoop;
	UINT32					NumRegions;
	PTILE_IMAGERY   TileSurf;
	TILE_ELEMENT		TileElement;

	// Loop through all surfaces and tiles and build database
	for( cnt1 = 0; cnt1 < (UINT32)giNumberOfTileTypes; cnt1++ )
	{
		// Get number of regions
		TileSurf = gTileSurfaceArray[ cnt1 ];

		if ( TileSurf != NULL )
		{

			// Build start index list
			gTileTypeStartIndex[ cnt1 ] = (UINT16)gTileDatabaseSize;

			NumRegions = TileSurf->vo->usNumberOfObjects;

			// Check for overflow
			if ( NumRegions > gNumTilesPerType[ cnt1 ] )
			{
				#ifdef JA2EDITOR
					// Display warning
					gfWarning = (UINT8)cnt1;
				#endif

				// Cutof
				NumRegions = gNumTilesPerType[ cnt1 ];
			}

			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Type: %s Size: %d Index: %d", gTileSurfaceName[cnt1], gNumTilesPerType[ cnt1 ], gTileDatabaseSize ) );

			for( cnt2 = 0; cnt2 < NumRegions; cnt2++ )
			{

				memset( &TileElement, 0, sizeof( TileElement ) );
				TileElement.usRegionIndex = (UINT16)cnt2;
				TileElement.hTileSurface	= TileSurf->vo;
				TileElement.sBuddyNum			= -1;

				// anv: additional tile properties
				TileElement.bWoodCamoAffinity		= TileSurf->bWoodCamoAffinity;
				TileElement.bDesertCamoAffinity		= TileSurf->bDesertCamoAffinity;
				TileElement.bUrbanCamoAffinity		= TileSurf->bUrbanCamoAffinity;
				TileElement.bSnowCamoAffinity		= TileSurf->bSnowCamoAffinity;

				TileElement.bCamoStanceModifer		= TileSurf->bCamoStanceModifer;
				TileElement.bSoundModifier			= TileSurf->bSoundModifier;
				TileElement.bStealthDifficultyModifer	= TileSurf->bStealthDifficultyModifer;

				TileElement.bTrapBonus	= TileSurf->bTrapBonus;

				TileElement.uiAdditionalFlags	= TileSurf->uiAdditionalFlags;

				// Check for multi-z stuff
				if ( TileSurf->vo->ppZStripInfo != NULL )
				{
					// Only do this if we are within the # of video objects
					if ( cnt2 < TileSurf->vo->usNumberOfObjects )
					{
						if ( TileSurf->vo->ppZStripInfo[ cnt2 ] != NULL )
						{
							TileElement.uiFlags |= MULTI_Z_TILE;
						}
					}
				}

				// Structure database stuff!
				if (TileSurf->pStructureFileRef != NULL && TileSurf->pStructureFileRef->pubStructureData != NULL)
				{
					if (TileSurf->pStructureFileRef->pDBStructureRef[cnt2].pDBStructure != NULL)
					{
						TileElement.pDBStructureRef	= &(TileSurf->pStructureFileRef->pDBStructureRef[cnt2]);

						if ( TileElement.pDBStructureRef->pDBStructure->fFlags & STRUCTURE_HIDDEN )
						{
							// ATE: These are ignored!
							//TileElement.uiFlags |= HIDDEN_TILE;
						}
					}
				}

				TileElement.fType							= (UINT16)TileSurf->fType;
				TileElement.ubTerrainID				= TileSurf->ubTerrainID;
				TileElement.usWallOrientation = NO_ORIENTATION;

				if (TileSurf->pAuxData != NULL)
				{
					if (TileSurf->pAuxData[cnt2].fFlags & AUX_FULL_TILE)
					{
						TileElement.ubFullTile = 1;
					}
					if (TileSurf->pAuxData[cnt2].fFlags & AUX_ANIMATED_TILE)
					{
						// Allocate Animated tile data
						AllocateAnimTileData( &TileElement, TileSurf->pAuxData[cnt2].ubNumberOfFrames );

						// Set values into tile element
						TileElement.pAnimData->bCurrentFrame = TileSurf->pAuxData[cnt2].ubCurrentFrame;
						for (ubLoop = 0; ubLoop < TileElement.pAnimData->ubNumFrames; ubLoop++)
						{
							TileElement.pAnimData->pusFrames[ ubLoop ] = gTileDatabaseSize - TileElement.pAnimData->bCurrentFrame + ubLoop;
						}

/*
						for (ubLoop = TileElement.pAnimData->bCurrentFrame; ubLoop < TileElement.pAnimData->ubNumFrames; ubLoop++)
						{
							TileElement.pAnimData->pusFrames[ ubLoop ] = gTileDatabaseSize - TileElement.pAnimData->bCurrentFrame + ubLoop;
						}
						for (ubLoop = 0; ubLoop < TileElement.pAnimData->bCurrentFrame; ubLoop++)
						{
							TileElement.pAnimData->pusFrames[ ubLoop ] = gTileDatabaseSize - TileElement.pAnimData->bCurrentFrame + ubLoop;
						}

*/
						Assert(gusNumAnimatedTiles < MAX_ANIMATED_TILES);

						// set into animation controller array
						gusAnimatedTiles[ gusNumAnimatedTiles ] = gTileDatabaseSize;
						gusNumAnimatedTiles++;						

						TileElement.uiFlags				|= ANIMATED_TILE;
					}
					TileElement.usWallOrientation = TileSurf->pAuxData[cnt2].ubWallOrientation;
					if (TileSurf->pAuxData[cnt2].ubNumberOfTiles > 0)
					{
						TileElement.ubNumberOfTiles = TileSurf->pAuxData[cnt2].ubNumberOfTiles;
						TileElement.pTileLocData = TileSurf->pTileLocData + TileSurf->pAuxData[cnt2].usTileLocIndex;
					}
				}

				SetSpecificDatabaseValues( (UINT16)cnt1, gTileDatabaseSize, &TileElement, TileSurf->bRaisedObjectType, iTilesetID );

				gTileDatabase[ gTileDatabaseSize ] = TileElement;
				gTileDatabaseSize++;
			}

			// Check if data matches what should be there
			if ( NumRegions < gNumTilesPerType[ cnt1 ] )
			{
				#ifdef JA2EDITOR
					// Display warning here
					gfWarning = (UINT8)cnt1;
				#endif

				// Do underflows here
				for ( cnt2 = NumRegions; cnt2 < gNumTilesPerType[ cnt1 ]; cnt2++ )
				{
					memset( &TileElement, 0, sizeof( TileElement ) );
					TileElement.usRegionIndex = 0;
					TileElement.hTileSurface	= TileSurf->vo;
					TileElement.fType					= (UINT16)TileSurf->fType;
					TileElement.ubFullTile	= FALSE;
					TileElement.sOffsetHeight = 0;
					TileElement.ubFullTile		= 0;
		  TileElement.uiFlags	   |= UNDERFLOW_FILLER;

					gTileDatabase[ gTileDatabaseSize ] = TileElement;
					gTileDatabaseSize++;
				}

			}

		}
	}

	//Calculate mem usgae
	gSurfaceMemUsage = guiMemTotal - gSurfaceMemUsage;
	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Database Sizes: %d vs %d", gTileDatabaseSize, giNumberOfTiles ) );
	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Database Types: %d", giNumberOfTileTypes ) );
	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Database Item Mem:		%d", gTileDatabaseSize * sizeof( TILE_ELEMENT ) ) );
	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Database Item Total Mem:		%d", gSurfaceMemUsage ) );

}

void DeallocateTileDatabase( )
{
	INT32 cnt;

	for( cnt = 0; cnt < giNumberOfTiles; cnt++ )
	{
		// Check if an existing set of animated tiles are in place, remove if found
		if ( gTileDatabase[ cnt ].pAnimData != NULL )
		{
			FreeAnimTileData( &gTileDatabase[ cnt ] );
		}
	}

	gTileDatabaseSize = 0;
	gSurfaceMemUsage = 0;
	gusNumAnimatedTiles = 0;

}


BOOLEAN GetLandHeadType( INT32 iMapIndex, UINT32 *puiType )
{
	Assert( puiType != NULL );

	CHECKF( gpWorldLevelData[ iMapIndex ].pLandHead != NULL );

	UINT16 usIndex = gpWorldLevelData[iMapIndex].pLandHead->usIndex;

	GetTileType( usIndex, puiType );

	return( TRUE );
}

BOOLEAN SetLandIndex( INT32 iMapIndex, UINT16 usIndex, UINT32 uiNewType, BOOLEAN fDelete )
{
	UINT16	usTempIndex;
	UINT8		ubLastHighLevel=0;

	if ( fDelete )
	{
		RemoveLand( iMapIndex, usIndex );
		return( TRUE );
	}

	if ( AnyHeigherLand( iMapIndex, uiNewType, &ubLastHighLevel ) )
	{
		// Check if type exists and get it's index if so
		if ( TypeExistsInLandLayer( iMapIndex, uiNewType, &usTempIndex ) )
		{
			// Replace with new index
			return( ReplaceLandIndex( iMapIndex, usTempIndex, usIndex ) );
		}
		else
		{
			return( InsertLandIndexAtLevel( iMapIndex, usIndex, (UINT8)(ubLastHighLevel+1) ) );
		}
	}
	else
	{
		// Check if type exists and get it's index if so
		if ( TypeExistsInLandLayer( iMapIndex, uiNewType, &usTempIndex ) )
		{
			// Replace with new index
			return( ReplaceLandIndex( iMapIndex, usTempIndex, usIndex ) );
		}
		else
		{
			// Otherwise, add to head
			return( AddLandToHead( iMapIndex, usIndex ) );
		}
	}
}


BOOLEAN SetLandIndexWithRadius( INT32 iMapIndex, UINT16 usIndex, UINT32 uiNewType, UINT8 ubRadius, BOOLEAN fReplace )
{
	UINT16				usTempIndex;
	INT16					sTop, sBottom;
	INT16					sLeft, sRight;
	INT16					cnt1, cnt2;
	INT32				iNewIndex;
	BOOLEAN				fDoPaste = FALSE;
	INT32					leftmost;
	//BOOLEAN				fNewCommand;
	UINT16				Dummy;

	// Determine start end end indicies and num rows
	sTop		= ubRadius;
	sBottom = -ubRadius;
	sLeft   = - ubRadius;
	sRight  = ubRadius;

	//fNewCommand = fFirstDrawMode; //NEW_UNDO_COMMAND;

	for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
	{

		leftmost = ( ( iMapIndex + ( WORLD_COLS * cnt1 ) )/ WORLD_COLS ) * WORLD_COLS;

		for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ )
		{
			iNewIndex = iMapIndex + ( WORLD_COLS * cnt1 ) + cnt2;

			if ( iNewIndex >=0 && iNewIndex < WORLD_MAX &&
				iNewIndex >= leftmost && iNewIndex < ( leftmost + WORLD_COLS ) )
			{

				if ( fReplace )
				{
					fDoPaste = TRUE;
				}
				else
				{
					if ( !TypeExistsInLandLayer( iNewIndex, uiNewType, &usTempIndex ) )
					{
						fDoPaste = TRUE;
					}
				}

				if ( fDoPaste && ((uiNewType >= FIRSTFLOOR && uiNewType <= LASTFLOOR) ||
												((uiNewType < FIRSTFLOOR || uiNewType > LASTFLOOR) &&
												!TypeRangeExistsInLandLayer( iNewIndex, FIRSTFLOOR, LASTFLOOR, &Dummy ))) )
				{
					SetLandIndex( iNewIndex, usIndex, uiNewType, FALSE );
				}
			}
		}
	}

	return( TRUE );
}


BOOLEAN GetTypeLandLevel( UINT32 iMapIndex, UINT32 uiNewType, UINT8 *pubLevel )
{
	UINT8					level = 0;
	LEVELNODE			*pLand;
	UINT32				fTileType=0;

	pLand = gpWorldLevelData[ iMapIndex ].pLandHead;

	while( pLand != NULL )
	{

		if ( pLand->usIndex != NO_TILE )
		{
			GetTileType( pLand->usIndex, &fTileType );

			if ( fTileType == uiNewType )
			{
				*pubLevel = level;
				return( TRUE );
			}

		}

		level++;
		pLand = pLand->pNext;
	}

	return( FALSE );

}


UINT8		GetLandLevelDepth( UINT32 iMapIndex )
{
	UINT8					level = 0;
	LEVELNODE		*pLand;

	pLand = gpWorldLevelData[ iMapIndex ].pLandHead;

	while( pLand != NULL )
	{
		level++;
		pLand = pLand->pNext;
	}

	return( level );

}

BOOLEAN GetSubIndexFromTileIndex( UINT16 usTileIndex, UINT16 *pusSubIndex )
{
	UINT32 uiType=0;
	*pusSubIndex = 0xffff;

	if( GetTileType( usTileIndex, &uiType ) )
	{
		*pusSubIndex = usTileIndex - gTileTypeStartIndex[ uiType ] + 1;
		return TRUE;
	}
	return FALSE;
}

BOOLEAN GetTypeSubIndexFromTileIndex( UINT32 uiCheckType, UINT16 usIndex, UINT16 *pusSubIndex )
{

	// Tile database is zero-based, Type indecies are 1-based!

	*pusSubIndex = 0xffff;

	CHECKF ( uiCheckType < (UINT32)giNumberOfTileTypes );

	*pusSubIndex = usIndex - gTileTypeStartIndex[ uiCheckType ] + 1;

	return( TRUE );
}

BOOLEAN GetTypeSubIndexFromTileIndexChar( UINT32 uiCheckType, UINT16 usIndex, UINT8 *pubSubIndex )
{
   *pubSubIndex = 0xff;

	// Tile database is zero-based, Type indecies are 1-based!

	CHECKF ( uiCheckType < (UINT32)giNumberOfTileTypes );

	*pubSubIndex = (UINT8)(usIndex - gTileTypeStartIndex[ uiCheckType ] + 1);

	return( TRUE );
}

BOOLEAN	GetTileIndexFromTypeSubIndex( UINT32 uiCheckType, UINT16 usSubIndex, UINT16 *pusTileIndex )
{
	// Tile database is zero-based, Type indecies are 1-based!

	*pusTileIndex = 0xffff;

	CHECKF ( uiCheckType < (UINT32)giNumberOfTileTypes );

	*pusTileIndex = usSubIndex + gTileTypeStartIndex[ uiCheckType ] - 1;

	return( TRUE );

}



BOOLEAN MoveLandIndexToTop( UINT32 iMapIndex, UINT16 usIndex )
{

	// Remove, then add again
	RemoveLand( iMapIndex, usIndex );

	AddLandToHead( iMapIndex, usIndex );

	return( TRUE );
}


// Database access functions
BOOLEAN	GetTileType( UINT16 usIndex, UINT32 *puiType )
{
  TILE_ELEMENT		TileElem;

	*puiType = 0xffffffff;

	CHECKF( usIndex != NO_TILE );
	CHECKF( usIndex < giNumberOfTiles ); //lal bugfix

	// Get tile element
	TileElem = gTileDatabase[ usIndex ];

	*puiType = TileElem.fType;

	return( TRUE );
}

BOOLEAN	GetTileFlags( UINT16 usIndex, UINT32 *puiFlags )
{
  TILE_ELEMENT		TileElem;

  *puiFlags = 0;

	CHECKF( usIndex != NO_TILE );
	CHECKF( usIndex < giNumberOfTiles );

	// Get tile element
	TileElem = gTileDatabase[ usIndex ];

	*puiFlags = TileElem.uiFlags;

	return( TRUE );
}

BOOLEAN	GetTileRegionIndex( UINT16 usIndex, UINT16& arRegionIndex )
{
	CHECKF( usIndex != NO_TILE );
	CHECKF( usIndex < giNumberOfTiles ); //lal bugfix
	
	arRegionIndex = gTileDatabase[usIndex].usRegionIndex;

	return( TRUE );
}

BOOLEAN	GetTileTypeLogicalHeight( UINT32 fType, UINT8 *pubLogHeight )
{
	*pubLogHeight = gTileTypeLogicalHeight[ fType ];

	return( TRUE );
}



BOOLEAN LandTypeHeigher( UINT32 uiDestType, UINT32 uiSrcType  )
{
  UINT8					ubDestLogHeight;
  UINT8					ubSrcLogHeight;

	// Get logical height of type at head and type we wish to paste
	GetTileTypeLogicalHeight( uiDestType, &ubDestLogHeight );
	GetTileTypeLogicalHeight( uiSrcType, &ubSrcLogHeight );

	return( ubDestLogHeight > ubSrcLogHeight );

}


BOOLEAN AnyHeigherLand( UINT32 iMapIndex, UINT32 uiSrcType, UINT8 *pubLastLevel )
{
	LEVELNODE		*pLand		= NULL;
  UINT8					ubSrcLogHeight=0;
	UINT32				fTileType=0;
	UINT8					level = 0;
	UINT8					ubSrcTypeLevel=0;
	BOOLEAN				fFound = FALSE;

	pLand = gpWorldLevelData[ iMapIndex ].pLandHead;

	GetTileTypeLogicalHeight( uiSrcType, &ubSrcLogHeight );

	// Check that src type is not head
	if ( GetTypeLandLevel( iMapIndex, uiSrcType, &ubSrcTypeLevel ) )
	{
		if ( ubSrcTypeLevel == LANDHEAD )
		{
				return( FALSE );
		}
	}

	// Look through all objects and Search for type

	while( pLand != NULL )
	{

		// Get type and height
		GetTileType( pLand->usIndex, &fTileType );

		if ( gTileTypeLogicalHeight[ fTileType ] > ubSrcLogHeight )
		{
			*pubLastLevel = level;
			fFound = TRUE;
		}

		// Advance to next
		pLand = pLand->pNext;

		level++;

	}

	// Could not find it, return FALSE
	return( fFound );

}

BOOLEAN AnyLowerLand( UINT32 iMapIndex, UINT32 uiSrcType, UINT8 *pubLastLevel )
{
	LEVELNODE		*pLand		= NULL;
  UINT8					ubSrcLogHeight;
	UINT32				fTileType=0;
	UINT8					level = 0;
	UINT8					ubSrcTypeLevel;
  TILE_ELEMENT		TileElem;

	pLand = gpWorldLevelData[ iMapIndex ].pLandHead;

	GetTileTypeLogicalHeight( uiSrcType, &ubSrcLogHeight );

	GetTypeLandLevel( iMapIndex, uiSrcType, &ubSrcTypeLevel );

	// Look through all objects and Search for type
	while( pLand != NULL )
	{

		// Get type and height
		GetTileType( pLand->usIndex, &fTileType );

		if ( gTileTypeLogicalHeight[ fTileType ] < ubSrcLogHeight )
		{
			*pubLastLevel = level;
			return( TRUE );
		}

		// Get tile element
		TileElem = gTileDatabase[ pLand->usIndex ];

		// Get full tile flag
		if ( TileElem.ubFullTile && fTileType != uiSrcType )
		{
			return( FALSE );
		}


		// Advance to next
		pLand = pLand->pNext;

		level++;

	}

	// Could not find it, return FALSE
	return( FALSE );

}


BOOLEAN GetWallOrientation( UINT16 usIndex, UINT16 *pusWallOrientation )
{
  TILE_ELEMENT		TileElem;

  	*pusWallOrientation = 0xffff;

  CHECKF( usIndex != NO_TILE );
	CHECKF( usIndex < giNumberOfTiles ); //lal bugfix

	// Get tile element
	TileElem = gTileDatabase[ usIndex ];

	*pusWallOrientation = TileElem.usWallOrientation;

	return( TRUE );
}

BOOLEAN ContainsWallOrientation( INT32 iMapIndex, UINT32 uiType, UINT16 usWallOrientation, UINT8 *pubLevel )
{
	LEVELNODE	*pStruct = NULL;
	UINT8					level = 0;
	UINT16				usCheckWallOrient=0;

	pStruct = gpWorldLevelData[ iMapIndex ].pStructHead;

	// Look through all objects and Search for type

	while( pStruct != NULL )
	{

		GetWallOrientation( pStruct->usIndex, &usCheckWallOrient );

		if ( usCheckWallOrient == usWallOrientation )
		{
				*pubLevel = level;
				return( TRUE );
		}

		// Advance to next
		pStruct = pStruct->pNext;

		level++;

	}

	// Could not find it, return FALSE
	return( FALSE );

}

//Kris:  This function returns two special types if there are two walls
//sharing the same tile.  This case only happens with the exterior and
//interior bottom corners.  Otherwise, it returns the orientation of the
//first wall encountered -- not that there should be duplicate walls...
UINT8 CalculateWallOrientationsAtGridNo( INT32 iMapIndex )
{
	UINT16 usCheckWallOrientation=0;
	LEVELNODE *pStruct = NULL;
	UINT8 ubFinalWallOrientation = NO_ORIENTATION;
	pStruct = gpWorldLevelData[ iMapIndex ].pStructHead;
	//Traverse all of the pStructs
	while( pStruct != NULL )
	{
		GetWallOrientation( pStruct->usIndex, &usCheckWallOrientation );
		if( ubFinalWallOrientation == NO_ORIENTATION )
		{	//Get the first valid orientation.
			ubFinalWallOrientation = (UINT8)usCheckWallOrientation;
		}
		else switch( ubFinalWallOrientation )
		{	//If the first valid orientation has the key counterpart orientation,
			//return the special corner orientations.
			case INSIDE_TOP_LEFT:
				if( usCheckWallOrientation == INSIDE_TOP_RIGHT )
					return INSIDE_BOTTOM_CORNER;
				break;
			case INSIDE_TOP_RIGHT:
				if( usCheckWallOrientation == INSIDE_TOP_LEFT )
					return INSIDE_BOTTOM_CORNER;
				break;
			case OUTSIDE_TOP_LEFT:
				if( usCheckWallOrientation == OUTSIDE_TOP_RIGHT )
					return OUTSIDE_BOTTOM_CORNER;
				break;
			case OUTSIDE_TOP_RIGHT:
				if( usCheckWallOrientation == OUTSIDE_TOP_LEFT )
					return OUTSIDE_BOTTOM_CORNER;
				break;
		}
		// Advance to next
		pStruct = pStruct->pNext;
	}
	// Only one wall, so return it's orienation.
	return ubFinalWallOrientation;
}


BOOLEAN AllocateAnimTileData( TILE_ELEMENT *pTileElem, UINT8 ubNumFrames )
{
	pTileElem->pAnimData = (TILE_ANIMATION_DATA *)MemAlloc( sizeof( TILE_ANIMATION_DATA ) );

	CHECKF( pTileElem->pAnimData != NULL );

	pTileElem->pAnimData->pusFrames = (UINT16 *)MemAlloc( sizeof( UINT16 ) * ubNumFrames );

	CHECKF( pTileElem->pAnimData->pusFrames != NULL );

	// Set # if frames!
	pTileElem->pAnimData->ubNumFrames = ubNumFrames;

	return( TRUE );
}

void FreeAnimTileData( TILE_ELEMENT *pTileElem )
{
	if ( pTileElem->pAnimData != NULL )
	{
		// Free frames list
		MemFree( pTileElem->pAnimData->pusFrames );

		// Free frames
		MemFree( pTileElem->pAnimData );
	}
}


