/***********************************************************************
 * maingame.C
 *  
 *    Main Game
 *
 *
 * Toby Opferman Copyright (c) 2003
 *
 ***********************************************************************/
 
 
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <gdi.h>
#include <gif.h>
#include <maploader.h>
#include <tile.h>
#include <Commdlg.h>
#include "leveleditorres.h"
#include "leveleditor.h"

#define NUMBER_OF_L1_TILES_X 16
#define NUMBER_OF_L1_TILES_Y 46
#define NUMBER_OF_L1_TILES (16*46)

typedef struct _LEVEL_TILE_DESCRIPTION
{
	DWORD  TileIndex;
	HGDI   hTileGdi;
	PUCHAR pTileBuffer;

	DWORD TileStartOffsetX;
	DWORD TileStartOffsetY;
	DWORD TileStride;
	
} LEVEL_TILE_DESCRIPTION, *PLEVEL_TILE_DESCRIPTION;

typedef enum _LEVEL_STATE
{
	NoLevelLoaded,
	LevelEditing

} LEVEL_STATE, *PLEVEL_STATE;

typedef struct _LEVEL_SCREEN
{
	HGDI hScreen;
	char *Buffer;

} LEVEL_SCREEN, *PLEVEL_SCREENR;

typedef struct _LEVEL_EDITOR
{
	HWND hWnd;
	HINSTANCE hInstance;

	LEVEL_SCREEN Screen;
	LEVEL_STATE  LevelState;
	BOOL         MapInfoAllocated;
	MAP_INFO     MapInfo;
	MAP_INFO     MapNoBlockingInfo;
	HTILE        hTile;
	HTILE        hTileSelection;
	LEVEL_TILE_DESCRIPTION TileDescription[NUMBER_OF_L1_TILES];
	HGDI         hTilesGDI;

	BOOL         KeyDown;
	BOOL         KeyUp;
	BOOL         KeyRight;
	BOOL         KeyLeft;

	BOOL         ToolsKeyDown;
	BOOL         ToolsKeyUp;
	BOOL         ToolsKeyRight;
	BOOL         ToolsKeyLeft;
	BOOL         AutoPaste;

	BOOL         AutoPilot;

	DWORD        dwFlags;

} LEVEL_EDITOR, *PLEVEL_EDITOR;

#define Ti(X, Y, F) ((X + Y*16) | (F<<24))

 /***********************************************************************
  * Prototypes
  ***********************************************************************/
void LevelEditor_Debug(char *pszFormatString, ...);
BOOL LevelEditor_CreateLevelScreen(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_NewLevel(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_LoadLevel(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_SaveLevel(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_CloseOpenMap(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_InitNewMap(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_CopyMapToNoBlock(PLEVEL_EDITOR pLevelEditor);
void WINAPI LevelEditor_DrawTile(PVOID pContext, DWORD dwTileId, UINT dwTileX, UINT dwTileY, UINT dwStartX, UINT dwStartY);
void WINAPI LevelEditor_DrawSprite(PVOID pContext, DWORD SpriteId, UINT uiStartX, UINT uiStartY, UINT ScreenX, UINT ScreenY);
BOOL LevelEditor_LoadTiles(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_UpdateScreen(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_HandleKeyDown(PLEVEL_EDITOR pLevelEditor, UINT vKey);
void LevelEditor_HandleKeyUp(PLEVEL_EDITOR pLevelEditor, UINT vKey);
BOOL WINAPI LevelEditor_NewLevelDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
void LevelEditor_InitTileSelection(PLEVEL_EDITOR pLevelEditor);
void LevelEditor_ReplaceTile(PLEVEL_EDITOR pLevelEditor);

 /***********************************************************************
  * LevelEditor_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
HLEVELEDITOR LevelEditor_Init(HWND hWnd, HINSTANCE hInstance)
{
	PLEVEL_EDITOR pLevelEditor;
	HDC hScreen;
	HDC hTitle;

	pLevelEditor = (PLEVEL_EDITOR)LocalAlloc(LMEM_ZEROINIT, sizeof(LEVEL_EDITOR));

	if(pLevelEditor)
	{
		pLevelEditor->hWnd       = hWnd;
		pLevelEditor->hInstance  = hInstance;
		pLevelEditor->LevelState = NoLevelLoaded;

		if(LevelEditor_LoadTiles(pLevelEditor))
		{
			if(LevelEditor_CreateLevelScreen(pLevelEditor))
			{
    			GDI_ClearVideoBuffer(pLevelEditor->Screen.hScreen);
				LevelEditor_InitTileSelection(pLevelEditor);
			}
			else
			{
				LocalFree(pLevelEditor);
				pLevelEditor = NULL;
			}
		}
		else
		{
			LocalFree(pLevelEditor);
			pLevelEditor = NULL;
		}

	}

	return pLevelEditor;
}



 /***********************************************************************
  * 
  *  LevelEditor_Close
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_Close(HLEVELEDITOR hLevelEditor)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;

	LocalFree(pLevelEditor);
}



 /***********************************************************************
  * LevelEditor_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_HandleKeyRelease(HLEVELEDITOR hLevelEditor, UINT vKey)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;

	switch(pLevelEditor->LevelState)
	{
		case LevelEditing:
			 LevelEditor_HandleKeyUp(pLevelEditor, vKey);
			 break;
	}
}



 /***********************************************************************
  * LevelEditor_HandleKeyUp
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_HandleKeyUp(PLEVEL_EDITOR pLevelEditor, UINT vKey)
{
	if(pLevelEditor->AutoPilot == FALSE)
	{
       pLevelEditor->KeyUp    = FALSE;
 	   pLevelEditor->KeyLeft  = FALSE;
 	   pLevelEditor->KeyRight = FALSE;
	   pLevelEditor->KeyDown  = FALSE;

       pLevelEditor->ToolsKeyUp    = FALSE;
 	   pLevelEditor->ToolsKeyLeft  = FALSE;
 	   pLevelEditor->ToolsKeyRight = FALSE;
	   pLevelEditor->ToolsKeyDown  = FALSE;
	}
}


 /***********************************************************************
  * LevelEditor_HandleKeyDown
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_HandleKeyDown(PLEVEL_EDITOR pLevelEditor, UINT vKey)
{
	switch(vKey)
	{
		case VK_UP:
	         pLevelEditor->KeyUp = TRUE;
			 break;

		case VK_LEFT:
			 pLevelEditor->KeyLeft = TRUE;
			 break;

		case VK_RIGHT:
			 pLevelEditor->KeyRight = TRUE;
			 break;

		case VK_DOWN:
			 pLevelEditor->KeyDown = TRUE;
			 break;

		case VK_NUMPAD8:
	         pLevelEditor->ToolsKeyUp = TRUE;
			 break;

		case VK_NUMPAD4:
			 pLevelEditor->ToolsKeyLeft = TRUE;
			 break;

		case VK_NUMPAD6:
			 pLevelEditor->ToolsKeyRight = TRUE;
			 break;

		case VK_NUMPAD2:
			 pLevelEditor->ToolsKeyDown = TRUE;
			 break;

		case VK_SPACE:
  			 LevelEditor_ReplaceTile(pLevelEditor);
			 break;

		case VK_F1:
			 pLevelEditor->dwFlags ^= TF_BLOCKED;
			 break;

		case VK_F2:
			 pLevelEditor->AutoPaste = !pLevelEditor->AutoPaste;
			 break;

		case VK_F3:
			 pLevelEditor->AutoPilot = !pLevelEditor->AutoPilot;
			 break;
	}
}


 /***********************************************************************
  * LevelEditor_ReplaceTile
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_ReplaceTile(PLEVEL_EDITOR pLevelEditor)
{
	TILE_LOCATION MapTileLocation;
	TILE_LOCATION TilesTileLocation;
	TILEINFO TileInfo = {0};
	UINT Index = 0;

	Tile_GetCurrentTileLocation(pLevelEditor->hTile, &MapTileLocation);
	Tile_GetCurrentTileLocation(pLevelEditor->hTileSelection, &TilesTileLocation);
	Index = MapTileLocation.dwCurrentTileX + MapTileLocation.dwCurrentTileY*pLevelEditor->MapNoBlockingInfo.MapResolutionX;

	pLevelEditor->MapNoBlockingInfo.MapData[Index] = Ti(TilesTileLocation.dwCurrentTileX, TilesTileLocation.dwCurrentTileY, 0);
	pLevelEditor->MapInfo.MapData[Index]           = Ti(TilesTileLocation.dwCurrentTileX, TilesTileLocation.dwCurrentTileY, pLevelEditor->dwFlags);
	TileInfo.dwTileId                              = Ti(TilesTileLocation.dwCurrentTileX, TilesTileLocation.dwCurrentTileY, 0);
	
	Tile_Modify(pLevelEditor->hTile, MapTileLocation.dwCurrentTileX, MapTileLocation.dwCurrentTileY, &TileInfo);
	LevelEditor_UpdateScreen(pLevelEditor);
}

 /***********************************************************************
  * LevelEditor_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_HandleKeyPress(HLEVELEDITOR hLevelEditor, UINT vKey)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;

	switch(pLevelEditor->LevelState)
	{
		case LevelEditing:
			 LevelEditor_HandleKeyDown(pLevelEditor, vKey);
			 break;
	}
}


 /***********************************************************************
  * LevelEditor_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
HDC LevelEditor_GetLevelDc(HLEVELEDITOR hLevelEditor)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;

    return GDI_GetDC(pLevelEditor->Screen.hScreen);
}

 /***********************************************************************
  * LevelEditor_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void LevelEditor_ReleaseLevelDc(HLEVELEDITOR hLevelEditor, HDC hLevelDC)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;
	GDI_ReleaseDC(pLevelEditor->Screen.hScreen);
}

 /***********************************************************************
  * LevelEditor_MessageLoop
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
BOOL LevelEditor_MessageLoop(HLEVELEDITOR hLevelEditor)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;
	TILE_LOCATION TileLocation;

	if(pLevelEditor->LevelState == LevelEditing)
	{
		if(pLevelEditor->KeyDown)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
			TileLocation.dwCurrentTileY++;
			Tile_SetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
		}

		if(pLevelEditor->KeyUp)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
			TileLocation.dwCurrentTileY--;
			Tile_SetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
		}

		if(pLevelEditor->KeyLeft)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
			TileLocation.dwCurrentTileX--;
			Tile_SetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
		}

		if(pLevelEditor->KeyRight)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
			TileLocation.dwCurrentTileX++;
			Tile_SetCurrentTileLocation(pLevelEditor->hTile, &TileLocation);
		}

		if(pLevelEditor->ToolsKeyDown)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
			TileLocation.dwCurrentTileY++;
			Tile_SetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
		}

		if(pLevelEditor->ToolsKeyUp)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
			TileLocation.dwCurrentTileY--;
			Tile_SetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
		}

		if(pLevelEditor->ToolsKeyLeft)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
			TileLocation.dwCurrentTileX--;
			Tile_SetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
		}

		if(pLevelEditor->ToolsKeyRight)
		{
			Tile_GetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
			TileLocation.dwCurrentTileX++;
			Tile_SetCurrentTileLocation(pLevelEditor->hTileSelection, &TileLocation);
		}


		if(pLevelEditor->AutoPaste)
		{
			LevelEditor_ReplaceTile(pLevelEditor);
		}

		LevelEditor_UpdateScreen(pLevelEditor);
	}

	SleepEx(30, TRUE);

	return TRUE;
}




 /***********************************************************************
  * LevelEditor_GenericLoadGif
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
HGDI LevelEditor_GenericLoadGif(PCHAR pszImageName, UINT uiImageNumber)
{
	HGDI hGdi;
	HGIF hGif;
	UINT Width;
	UINT Height;
	PCHAR ScreenBuffer;

	hGif = Gif_Open(pszImageName);

	if(hGif)
	{
		Width  = Gif_GetImageWidth(hGif, uiImageNumber);
    	Height = Gif_GetImageHeight(hGif, uiImageNumber);

		hGdi = GDI_Init(NULL, Width, Height);

		if(hGdi)
		{
			ScreenBuffer = GDI_BeginPaint(hGdi);
			Gif_GetImage32bpp(hGif, uiImageNumber, ScreenBuffer);
			GDI_EndPaint(hGdi);
		}

		Gif_Close(hGif);
	}

	return hGdi;
}



/***********************************************************************
 * LevelEditor_Debug
 *  
 *    Debug Shit
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
 void LevelEditor_Debug(char *pszFormatString, ...)
 {
     char DebugString[256];
     va_list vl;

     va_start(vl, pszFormatString);
     vsprintf(DebugString, pszFormatString, vl);
     va_end(vl);

     OutputDebugStringA(DebugString);
 }


/***********************************************************************
 * LevelEditor_NewLevel
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_NewLevel(PLEVEL_EDITOR pLevelEditor)
{
	UINT Index;
	if(DialogBoxParam(pLevelEditor->hInstance, MAKEINTRESOURCE(IDD_NEW_LEVEL_DLG), pLevelEditor->hWnd, LevelEditor_NewLevelDialog, (LPARAM)pLevelEditor))
	{
		pLevelEditor->MapInfo.MapData = (DWORD *)LocalAlloc(LMEM_ZEROINIT, pLevelEditor->MapInfo.MapResolutionX*pLevelEditor->MapInfo.MapResolutionY*4);
		pLevelEditor->MapInfoAllocated = TRUE;

		for(Index = 0; Index < pLevelEditor->MapInfo.MapResolutionX*pLevelEditor->MapInfo.MapResolutionY; Index++)
		{
			pLevelEditor->MapInfo.MapData[Index] = Ti(14, 7, 0);
		}

		LevelEditor_InitNewMap(pLevelEditor);
	}
}

/***********************************************************************
 * LevelEditor_LoadLevel
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_LoadLevel(PLEVEL_EDITOR pLevelEditor)
{
	OPENFILENAME OpenFileName = {0};
	char szFileName[1024] = {0};
	BOOL LoadNewMap = TRUE;
	char *pszExtFilter = "*.MAP\0\0";

	if(pLevelEditor->LevelState == LevelEditing)
	{
		LoadNewMap = FALSE;
		if(MessageBox(pLevelEditor->hWnd, "Failed to load map", "Map Load Failure", MB_YESNO) == IDYES)
		{
			LoadNewMap = TRUE;
			LevelEditor_CloseOpenMap(pLevelEditor);
		}
	}


	if(LoadNewMap)
	{
		OpenFileName.lStructSize = sizeof(OpenFileName);
		OpenFileName.hwndOwner   = pLevelEditor->hWnd;
		OpenFileName.hInstance   = pLevelEditor->hInstance;
		OpenFileName.hInstance   = pLevelEditor->hInstance;
		OpenFileName.Flags       = 0;
		OpenFileName.lpstrFile   = szFileName;
		OpenFileName.nMaxFile    = sizeof(szFileName);
     	OpenFileName.lpstrFilter = pszExtFilter;
		OpenFileName.lpstrDefExt = "MAP";

		if(GetOpenFileName(&OpenFileName))
		{
			if(MapLoader_LoadMap(szFileName, &pLevelEditor->MapInfo) == FALSE)
			{
				MessageBox(pLevelEditor->hWnd, "Failed to load map", "Map Load Failure", MB_OK | MB_ICONWARNING);
			}
			else
			{
				LevelEditor_InitNewMap(pLevelEditor);
			}
		}
	}
}


/***********************************************************************
 * LevelEditor_SaveLevel
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_SaveLevel(PLEVEL_EDITOR pLevelEditor)
{
	OPENFILENAME OpenFileName = {0};
	char szFileName[1024] = {0};
	char *pszExtFilter = "*.MAP\0\0";

	OpenFileName.lStructSize = sizeof(OpenFileName);
	OpenFileName.hwndOwner   = pLevelEditor->hWnd;
	OpenFileName.hInstance   = pLevelEditor->hInstance;
	OpenFileName.hInstance   = pLevelEditor->hInstance;
	OpenFileName.Flags       = OFN_OVERWRITEPROMPT;
	OpenFileName.lpstrFile   = szFileName;
	OpenFileName.nMaxFile    = sizeof(szFileName);
	OpenFileName.lpstrFilter = pszExtFilter;
	OpenFileName.lpstrDefExt = "MAP";
     
	if(GetSaveFileName(&OpenFileName))
	{
		if(MapLoader_SaveMap(szFileName, &pLevelEditor->MapInfo) == FALSE)
		{
			MessageBox(pLevelEditor->hWnd, "Failed to save map", "Map Save Failure", MB_OK | MB_ICONWARNING);
		}
	}
}



/***********************************************************************
 * LevelEditor_CreateLevelScreen
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL LevelEditor_CreateLevelScreen(PLEVEL_EDITOR pLevelEditor)
{
	BOOL Status = FALSE;

    pLevelEditor->Screen.hScreen = GDI_Init(NULL, GAME_WIDTH, GAME_HEIGHT + GAME_HEIGHT_BOTTOM + 5);

    if(pLevelEditor->Screen.hScreen)
    {
		Status = TRUE;
    }

	return Status;
}


/***********************************************************************
 * LevelEditor_HandleMenuCommands
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_HandleMenuCommands(HLEVELEDITOR hLevelEditor, USHORT Command, LPARAM lParam)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)hLevelEditor;

	switch(Command)
	{
		case IDM_ABOUT:
			 break;

		case IDM_NEW_LEVEL:
			 LevelEditor_NewLevel(pLevelEditor);
			 break;

		case IDM_LOAD_LEVEL:
			 LevelEditor_LoadLevel(pLevelEditor);
			 break;

		case IDM_SAVE_LEVEL:
			 LevelEditor_SaveLevel(pLevelEditor);
			 break;

		case IDM_EXIT:
			 SendMessage(pLevelEditor->hWnd, WM_CLOSE, 0, 0);
			 break;
	}
}


/***********************************************************************
 * LevelEditor_CloseOpenMap
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_CloseOpenMap(PLEVEL_EDITOR pLevelEditor)
{
	EnableMenuItem(GetMenu(pLevelEditor->hWnd), IDM_SAVE_LEVEL, MF_GRAYED);
	pLevelEditor->LevelState = NoLevelLoaded;

	if(pLevelEditor->MapInfoAllocated)
	{
		LocalFree(pLevelEditor->MapInfo.MapData);
	}
	else
	{
		MapLoader_FreeMap(&pLevelEditor->MapInfo);
	}

	pLevelEditor->MapInfoAllocated = FALSE;

	LocalFree(pLevelEditor->MapNoBlockingInfo.MapData);
	Tile_UnInit(pLevelEditor->hTile);
	pLevelEditor->hTile = NULL;	
}


/***********************************************************************
 * LevelEditor_InitTileSelection
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_InitTileSelection(PLEVEL_EDITOR pLevelEditor)
{
	TILE_MAP TileMap;
	UINT NumberOfTiles;
	PTILEINFO pTileInfo;
	UINT Index;


	TileMap.pTileContext  = pLevelEditor;
	TileMap.pfnDrawTile   = LevelEditor_DrawTile;
	TileMap.pfnDrawSprite = LevelEditor_DrawSprite;
	TileMap.dwResolutionX = NUMBER_OF_L1_TILES_X;
	TileMap.dwResolutionY = NUMBER_OF_L1_TILES_Y;
	TileMap.dwTileSizeX = 48;
	TileMap.dwTileSizeY = 48;
	TileMap.dwCurrentTileX = 0;
	TileMap.dwCurrentTileY = 0;
	TileMap.dwViewWidth  = 48;
	TileMap.dwViewHeight = 48;

    NumberOfTiles = NUMBER_OF_L1_TILES;

    pTileInfo = (PTILEINFO)LocalAlloc(LMEM_ZEROINIT, sizeof(TILEINFO)*NumberOfTiles);

    if(pTileInfo)
    {
	   for(Index = 0; Index < NumberOfTiles; Index++)
	   {
		   pTileInfo[Index].dwTileId    = Index;
		   pTileInfo[Index].dwTileFlags = 0;
	   }

	   TileMap.pTileInfo = pTileInfo;

	   pLevelEditor->hTileSelection = Tile_Init(&TileMap);

	   LocalFree(pTileInfo);
	}
}



/***********************************************************************
 * LevelEditor_InitNewMap
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_InitNewMap(PLEVEL_EDITOR pLevelEditor)
{
	TILE_MAP TileMap;
	UINT NumberOfTiles;
	PTILEINFO pTileInfo;
	UINT Index;

	EnableMenuItem(GetMenu(pLevelEditor->hWnd), IDM_SAVE_LEVEL, MF_ENABLED);
	pLevelEditor->LevelState = LevelEditing;
	LevelEditor_CopyMapToNoBlock(pLevelEditor);

	TileMap.pTileContext  = pLevelEditor;
	TileMap.pfnDrawTile   = LevelEditor_DrawTile;
	TileMap.pfnDrawSprite = LevelEditor_DrawSprite;
	TileMap.dwResolutionX = pLevelEditor->MapNoBlockingInfo.MapResolutionX;
	TileMap.dwResolutionY = pLevelEditor->MapNoBlockingInfo.MapResolutionY;
	TileMap.dwTileSizeX = 48;
	TileMap.dwTileSizeY = 48;
	TileMap.dwCurrentTileX = 0;
	TileMap.dwCurrentTileY = 0;
	TileMap.dwViewWidth  = 48;
	TileMap.dwViewHeight = 48;

    NumberOfTiles = TileMap.dwResolutionX*TileMap.dwResolutionY;

    pTileInfo = (PTILEINFO)LocalAlloc(LMEM_ZEROINIT, sizeof(TILEINFO)*NumberOfTiles);

    if(pTileInfo)
    {
	   for(Index = 0; Index < NumberOfTiles; Index++)
	   {
		   pTileInfo[Index].dwTileId    = pLevelEditor->MapNoBlockingInfo.MapData[Index];
		   pTileInfo[Index].dwTileFlags = 0;
	   }

	   TileMap.pTileInfo = pTileInfo;

	   pLevelEditor->hTile = Tile_Init(&TileMap);

	   LocalFree(pTileInfo);
	}

	LevelEditor_UpdateScreen(pLevelEditor);
}




/***********************************************************************
 * LevelEditor_CopyMapToNoBlock
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_CopyMapToNoBlock(PLEVEL_EDITOR pLevelEditor)
{
	UINT Index;
	pLevelEditor->MapNoBlockingInfo.MapResolutionX = pLevelEditor->MapInfo.MapResolutionX;
	pLevelEditor->MapNoBlockingInfo.MapResolutionY = pLevelEditor->MapInfo.MapResolutionY;
	pLevelEditor->MapNoBlockingInfo.MapData        = (DWORD *)LocalAlloc(LMEM_ZEROINIT, sizeof(DWORD)*pLevelEditor->MapInfo.MapResolutionY*pLevelEditor->MapInfo.MapResolutionX);

	if(pLevelEditor->MapNoBlockingInfo.MapData)
	{
		for(Index = 0; Index < pLevelEditor->MapInfo.MapResolutionY*pLevelEditor->MapInfo.MapResolutionX; Index++)
		{
			pLevelEditor->MapNoBlockingInfo.MapData[Index] = (pLevelEditor->MapInfo.MapData[Index] & 0xFFFFFF);
		}
	}
}


/***********************************************************************
 * LevelEditor_DrawTile
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void WINAPI LevelEditor_DrawTile(PVOID pContext, DWORD dwTileId, UINT dwTileX, UINT dwTileY, UINT dwStartX, UINT dwStartY)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)pContext;
	PLEVEL_TILE_DESCRIPTION pTileDescription;
	DWORD StartIndexX;
	DWORD StartIndexY;
	DWORD CopySize;

	/*
	 * Future: Do a look up table here for tiles not in a sorted ordering
	 */
	pTileDescription = &pLevelEditor->TileDescription[dwTileId];

	StartIndexX = pTileDescription->TileStartOffsetX;
	StartIndexY = pTileDescription->TileStartOffsetY;
    
	/*
	 * Assume everything is in range, for now
	 */
	{
		for(; dwStartY < 48 && dwTileY < GAME_HEIGHT; dwStartY++, dwTileY++)
		{
			
			CopySize = 48 - dwStartX;

			if(CopySize + dwTileX >= GAME_WIDTH)
			{
				CopySize = CopySize - ((CopySize + dwTileX) - GAME_WIDTH);
			}

			memcpy(&pLevelEditor->Screen.Buffer[(dwTileX<<2) + ((dwTileY<<2)*GAME_WIDTH)], 
				   &pTileDescription->pTileBuffer[((StartIndexX+dwStartX)<<2) + (((StartIndexY+dwStartY)<<2)*pTileDescription->TileStride)],
				   CopySize<<2);
		}
	}
}

/***********************************************************************
 * LevelEditor_DrawSprite
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void WINAPI LevelEditor_DrawSprite(PVOID pContext, DWORD SpriteId, UINT uiStartX, UINT uiStartY, UINT ScreenX, UINT ScreenY)
{
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)pContext;
	UINT CopySize;

	CopySize = 48 - uiStartX;

	if(CopySize + ScreenX >= GAME_WIDTH)
	{
		CopySize = CopySize - ((CopySize + ScreenX) - GAME_WIDTH);
	}

	for(; ScreenY < GAME_HEIGHT && uiStartY < 48; uiStartY++, ScreenY++)
	{
		if(uiStartY == 0 || uiStartY == 47)
		{
			memset(&pLevelEditor->Screen.Buffer[(ScreenX<<2) + ((ScreenY<<2)*GAME_WIDTH)], 0xFF, CopySize<<2);
		}
		else
		{
			memset(&pLevelEditor->Screen.Buffer[(ScreenX<<2) + ((ScreenY<<2)*GAME_WIDTH)], 0xFF, 4);
			memset(&pLevelEditor->Screen.Buffer[((ScreenX + CopySize - 1)<<2) + ((ScreenY<<2)*GAME_WIDTH)], 0xFF, 4);
		}
	}
}


/***********************************************************************
 * LevelEditor_LoadTiles
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL LevelEditor_LoadTiles(PLEVEL_EDITOR pLevelEditor)
{
	pLevelEditor->hTilesGDI = LevelEditor_GenericLoadGif("tiles1.gif", 0);

	if(pLevelEditor->hTilesGDI)
	{
		BOOL Status = FALSE;
		UINT IndexX;
		UINT IndexY;
		UINT Index;
		char *pBuffer;

		pBuffer = GDI_BeginPaint(pLevelEditor->hTilesGDI);
		Status = TRUE;

		for(Index = 0, IndexY = 0; IndexY < NUMBER_OF_L1_TILES_Y; IndexY++)
		{
			for(IndexX = 0; IndexX < NUMBER_OF_L1_TILES_X; IndexX++, Index++)
			{
				pLevelEditor->TileDescription[Index].TileIndex   = Index;
				pLevelEditor->TileDescription[Index].hTileGdi    = pLevelEditor->hTilesGDI;
				pLevelEditor->TileDescription[Index].pTileBuffer = pBuffer;
				pLevelEditor->TileDescription[Index].TileStartOffsetX = (3*IndexX) + 2 + (IndexX*48);
				pLevelEditor->TileDescription[Index].TileStartOffsetY = (3*IndexY) + 2 + (IndexY*48);
				pLevelEditor->TileDescription[Index].TileStride  = 816; // Change this later to not be hard coded here
			}
		}
	}

	return TRUE;
}


/***********************************************************************
 * LevelEditor_UpdateScreen
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void LevelEditor_UpdateScreen(PLEVEL_EDITOR pLevelEditor)
{
	pLevelEditor->Screen.Buffer = GDI_BeginPaint(pLevelEditor->Screen.hScreen);
    
	Tile_Draw(pLevelEditor->hTile, GAME_WIDTH, GAME_HEIGHT);

	pLevelEditor->Screen.Buffer = pLevelEditor->Screen.Buffer + (GAME_HEIGHT*GAME_WIDTH*4);

	Tile_Draw(pLevelEditor->hTileSelection, GAME_WIDTH, GAME_HEIGHT_BOTTOM); // 48*16
		
    GDI_EndPaint(pLevelEditor->Screen.hScreen);
	pLevelEditor->Screen.Buffer = NULL;

	if(pLevelEditor->dwFlags & TF_BLOCKED || pLevelEditor->AutoPaste || pLevelEditor->AutoPilot)
	{
		HDC hDC;
		char szGameBufferText[100];

		hDC = GDI_GetDC(pLevelEditor->Screen.hScreen);

		SetBkMode(hDC, TRANSPARENT);                            
		SetTextColor(hDC, 0xFFFFFF);

		if(pLevelEditor->dwFlags & TF_BLOCKED)
		{
			sprintf(szGameBufferText, "Blocked Tile Enabled");
			TextOut(hDC, 10, 10, szGameBufferText, strlen(szGameBufferText));
		}

		if(pLevelEditor->AutoPilot)
		{
			sprintf(szGameBufferText, "Autopilot Enabled");
			TextOut(hDC, 10, 25, szGameBufferText, strlen(szGameBufferText));
		}

		if(pLevelEditor->AutoPaste)
		{
			sprintf(szGameBufferText, "Autopaste Enabled");
			TextOut(hDC, 10, 40, szGameBufferText, strlen(szGameBufferText));
		}


		GDI_ReleaseDC(pLevelEditor->Screen.hScreen);
	}	

	InvalidateRect(pLevelEditor->hWnd, NULL, FALSE);
}


/***********************************************************************
 * LevelEditor_NewLevelDialog
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL WINAPI LevelEditor_NewLevelDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	BOOL RetVal = FALSE;
	PLEVEL_EDITOR pLevelEditor = (PLEVEL_EDITOR)GetWindowLong(hWnd, GWL_USERDATA);

	switch(Msg)
	{
	    case WM_INITDIALOG:
			 SetWindowLong(hWnd, GWL_USERDATA, (LPARAM)lParam);
			 RetVal = TRUE;
			 break;

		case WM_COMMAND:
			 switch(LOWORD(wParam))
			 {
				 case IDCANCEL:
					  EndDialog(hWnd, FALSE);
					  break;
				 case IDOK:
 					  pLevelEditor->MapInfo.MapResolutionX = GetDlgItemInt(hWnd, IDC_RES_X, NULL, FALSE);
					  pLevelEditor->MapInfo.MapResolutionY = GetDlgItemInt(hWnd, IDC_RES_Y, NULL, FALSE);
					  EndDialog(hWnd, TRUE);
 					  break;
			 }
			 break;
	}
		 

	return RetVal;
}