// AMMap.cpp: implementation of the CAMMap class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Test1.h"
#include "AMMap.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

LPDIRECTDRAW2 STileSet::s_lpDD = NULL;
STileSet* STileSet::s_pTileSet[256];


BOOL STileSet::LoadTile()
{
	ReleaseTile();

	HANDLE hFile;
	DWORD dwBytesRead;

	ODS("Load Tile : %s\n", strName);
	hFile = CreateFile(strName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile)
	{
		// 타일 서피스를 시스템 메모리에 만들려면 아래것을
		m_pTileSurface = g_DXDraw.CreateSurface(TILE_WIDTH * TILESET_WIDTH, TILE_HEIGHT * TILESET_HEIGHT, DDSCAPS_SYSTEMMEMORY);
		// 타일 서피스를 비디오 메모리에 만들려면 아래것을
		// m_pTileSurface = g_DXDraw.CreateSurface(TILE_WIDTH * TILESET_WIDTH, TILE_HEIGHT * TILESET_HEIGHT, DDSCAPS_VIDEOMEMORY);
		DDSURFACEDESC ddsd = m_pTileSurface->Lock();
		for (int i = 0;i < TILE_HEIGHT * TILESET_HEIGHT;i++)
			ReadFile(hFile, (LPBYTE)ddsd.lpSurface + ddsd.lPitch * i, TILE_WIDTH * TILESET_WIDTH * sizeof(WORD), &dwBytesRead, NULL);
		m_pTileSurface->Unlock();
		m_pTileSurface->SetColorKey(0);
		CloseHandle(hFile);
	}
	else
		AfxMessageBox("Load Tile Failed");
	return TRUE;
}


void STileSet::ReleaseTile()
{
	if (m_pTileSurface)
		delete m_pTileSurface;
	m_pTileSurface = NULL;
	nUsed = 0;
}

void STileSet::DrawTile(int nX, int nY, int nTileNum, CDXSurface* pSurface)
{
	int nSrcX = (nTileNum % TILESET_WIDTH) * TILE_WIDTH;
	int nSrcY = (nTileNum / TILESET_WIDTH) * TILE_HEIGHT;

	pSurface->Blt(nX, nY, m_pTileSurface, CRect(nSrcX, nSrcY, nSrcX + TILE_WIDTH, nSrcY + TILE_HEIGHT), DDBLTFAST_SRCCOLORKEY);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAMMap::CAMMap()
{
	m_ptInterimBase.x = -1;
	m_ptInterimBase.y = -1;
	m_sizeMap = CSize(-1, -1);
	m_pInterimBuf = NULL;
	m_pMapCell = NULL;
}

CAMMap::~CAMMap()
{
	POSITION pos = m_listTileSet.GetHeadPosition();
	STileSet* pTileSet;

	while (pos)
	{
		pTileSet = m_listTileSet.GetNext(pos);
		delete pTileSet;
	}
	m_listTileSet.RemoveAll();

	if (m_pInterimBuf)
		delete m_pInterimBuf;
	if (m_pMapCell)
		free(m_pMapCell);
}

BOOL CAMMap::Create(int nScreenTileWidth, int nScreenTileHeight, LPCTSTR lpszFilePath)
{
	m_szInterimBuf = CSize(nScreenTileWidth + 1, nScreenTileHeight + 1);
	m_pInterimBuf = g_DXDraw.CreateSurface(m_szInterimBuf.cx * TILE_WIDTH, m_szInterimBuf.cy * TILE_HEIGHT);
	if (m_pInterimBuf == NULL)
	{
		AfxMessageBox("Interim Buf Error");
		return FALSE;
	}
	return LoadMap(lpszFilePath);
}

BOOL CAMMap::LoadMap(LPCTSTR strFilePath)
{
	CFile file;
	
	if (file.Open(strFilePath, CFile::modeRead))
	{
		CFile file2;
		CArchive ar(&file, CArchive::load);
		m_strFilePath = strFilePath;

		CString strMapSpec;
		BYTE cVerHigh, cVerLow;

		ar >> strMapSpec;
		ar >> cVerHigh >> cVerLow;

		ar >> m_sizeMap.cx >> m_sizeMap.cy;
		m_pMapCell = (SMapCell *)malloc(m_sizeMap.cx * m_sizeMap.cy * sizeof(SMapCell));

		ar.Read(m_pMapCell, m_sizeMap.cx * m_sizeMap.cy * sizeof(SMapCell));
		
		int nTileSetCount;

		ar >> nTileSetCount;

		CString strName, strFilePath;
		STileSet* pTileSet;
		BYTE cID;
		int nHotKey;

		while (nTileSetCount--)
		{
			ar >> cID >> strName >> strFilePath >> nHotKey;
			pTileSet = AddTileSet(strName, strFilePath, cID);
		}
		return TRUE;
	}
	else
		return FALSE;
}


STileSet* CAMMap::AddTileSet(CString strName, CString strFilePath, BYTE cID)
{
	STileSet* pTileSet;
	pTileSet = new STileSet(cID);

	pTileSet->strName = strName;
	pTileSet->strFilePath = strFilePath;
	if (pTileSet->LoadTile())
	{
		m_listTileSet.AddTail(pTileSet);
		return pTileSet;
	}
	else
	{
		delete pTileSet;
		return NULL;
	}
}


void CAMMap::DrawMap2(int nViewTileX, int nViewTileY, CDXSurface *pSurface)
{
	STileSet* pTileSet;
	SMapCell* pMapCell;

	int i, j;


	for (i = 0; i < 15;i++)
	{
		for (j = 0; j < 20;j++)
		{
			pMapCell = &m_pMapCell[(nViewTileY + i) * m_sizeMap.cx + nViewTileX + j];
			pTileSet = GetTileSet(pMapCell->cBaseTileSet);
			if (pTileSet)
				pTileSet->DrawTile(j * TILE_WIDTH, i * TILE_HEIGHT, pMapCell->cBaseTileNumber, pSurface);
		}
	}
}


void CAMMap::DrawMap(int nX, int nY, CDXSurface *pSurface)
{
	CRect rect;
	int nLeft, nTop, nRight, nBottom;
	BOOL bHorzDivide;
	BOOL bVertDivide;
	CSize sizeIntBuf;

	sizeIntBuf = CSize(m_szInterimBuf.cx * TILE_WIDTH, m_szInterimBuf.cy * TILE_HEIGHT);

	nLeft	= nX % sizeIntBuf.cx;
	nTop	= nY % sizeIntBuf.cy;
	nRight	= (nX + (m_szInterimBuf.cx - 1) * TILE_WIDTH) % sizeIntBuf.cx;
	nBottom = (nY + (m_szInterimBuf.cy - 1) * TILE_HEIGHT) % sizeIntBuf.cy;

	bHorzDivide = (nLeft > nRight) && (nRight != 0);
	bVertDivide = (nTop > nBottom) && (nBottom != 0);
	if (nRight == 0)
		nRight = sizeIntBuf.cx;
	if (nBottom == 0)
		nBottom = sizeIntBuf.cy;
	if (!bHorzDivide && !bVertDivide)
		pSurface->Blt(0, 0, m_pInterimBuf, CRect(nLeft, nTop, nRight, nBottom));
	else if (bHorzDivide && bVertDivide)
	{
		pSurface->Blt(0, 0, m_pInterimBuf, 
			CRect(nLeft, nTop, sizeIntBuf.cx, sizeIntBuf.cy));
		pSurface->Blt(sizeIntBuf.cx - nLeft, 0, m_pInterimBuf,
			CRect(0, nTop, nRight, sizeIntBuf.cy));
		pSurface->Blt(0, sizeIntBuf.cy - nTop, m_pInterimBuf,
			CRect(nLeft, 0, sizeIntBuf.cx, nBottom));
		pSurface->Blt(sizeIntBuf.cx - nLeft, sizeIntBuf.cy - nTop, m_pInterimBuf,
			CRect(0, 0, nRight, nBottom));
	}
	else if (bHorzDivide)
	{
		pSurface->Blt(0, 0, m_pInterimBuf,
			CRect(nLeft, nTop, sizeIntBuf.cx, nBottom));
		pSurface->Blt(sizeIntBuf.cx - nLeft, 0, m_pInterimBuf,
			CRect(0, nTop, nRight, nBottom));
	}
	else
	{
		pSurface->Blt(0, 0, m_pInterimBuf,
			CRect(nLeft, nTop, nRight, sizeIntBuf.cy));
		pSurface->Blt(0, sizeIntBuf.cy - nTop, m_pInterimBuf,
			CRect(nLeft, 0, nRight, nBottom));
	}
}


void CAMMap::DrawCellToInterim(int nX, int nY)
{
	STileSet* pTileSet;
	SMapCell* pMapCell;

	pMapCell = &m_pMapCell[nY * m_sizeMap.cx + nX];
	pTileSet = GetTileSet(pMapCell->cBaseTileSet);
	if (pTileSet)
		pTileSet->DrawTile((nX % m_szInterimBuf.cx) * TILE_WIDTH, (nY % m_szInterimBuf.cy) * TILE_HEIGHT, pMapCell->cBaseTileNumber, m_pInterimBuf);
	/*
	else
	{
		CRect rectDest;

		rectDest.left	= (nX % m_szInterimBuf.cx) * TILE_WIDTH;
		rectDest.top	= (nY % m_szInterimBuf.cy) * TILE_HEIGHT;
		rectDest.right	= rectDest.left + TILE_WIDTH;
		rectDest.bottom	= rectDest.top + TILE_HEIGHT;
		m_pInterimBuf->FillColor(rectDest, 0);
	}
	*/

	if (pMapCell->cSpriteTileSet && pMapCell->cSpriteTileNumber)
	{
		pTileSet = GetTileSet(pMapCell->cSpriteTileSet);
		if (pTileSet)
			pTileSet->DrawTile((nX % m_szInterimBuf.cx) * TILE_WIDTH, (nY % m_szInterimBuf.cy) * TILE_HEIGHT, pMapCell->cSpriteTileNumber, m_pInterimBuf);
	}
}


void CAMMap::DrawInterimBuf(int nTX, int nTY)
{
	m_ptInterimBase = CPoint(nTX, nTY);
	int nX, nY;

	for (nY = nTY; nY < nTY + m_szInterimBuf.cy; nY++)
		for (nX = nTX; nX < nTX + m_szInterimBuf.cx; nX++)
			DrawCellToInterim(nX, nY);
}


STileSet* CAMMap::GetTileSet(BYTE cID)
{
	STileSet* pTileSet;

	pTileSet = STileSet::s_pTileSet[cID];
	if (pTileSet == NULL)
		return NULL;
	return pTileSet;
}


void CAMMap::SetViewPosition(int nViewTileX, int nViewTileY)
{
	int nScrollX = nViewTileX - m_ptInterimBase.x;
	int nScrollY = nViewTileY - m_ptInterimBase.y;

	if ((m_ptInterimBase.x == -1) || (m_ptInterimBase.y == -1) ||
		(abs(nScrollX) > m_szInterimBuf.cx / 2) || (abs(nScrollY) > m_szInterimBuf.cy / 2))
	{
		DrawInterimBuf(nViewTileX, nViewTileY);
	}
	else
	{
		if (nScrollX != 0)
			ScrollHorz(nScrollX);
		if (nScrollY != 0)
			ScrollVert(nScrollY);
	}
}

void CAMMap::ScrollHorz(int nScroll)
{
	m_ptInterimBase.x += nScroll;
	int nX, nY;

	if (nScroll > 0)
	{
		for (nY = m_ptInterimBase.y; nY < m_ptInterimBase.y + m_szInterimBuf.cy; nY++)
			for (nX = m_ptInterimBase.x + m_szInterimBuf.cx - nScroll; nX < m_ptInterimBase.x + m_szInterimBuf.cx; nX++)
				DrawCellToInterim(nX, nY);
	}
	else
	{
		for (nY = m_ptInterimBase.y; nY < m_ptInterimBase.y + m_szInterimBuf.cy; nY++)
			for (nX = m_ptInterimBase.x; nX < m_ptInterimBase.x - nScroll; nX++)
				DrawCellToInterim(nX, nY);
	}
}

void CAMMap::ScrollVert(int nScroll)
{
	m_ptInterimBase.y += nScroll;
	int nX, nY;

	if (nScroll > 0)
	{
		for (nY = m_ptInterimBase.y + m_szInterimBuf.cy - nScroll; nY < m_ptInterimBase.y + m_szInterimBuf.cy; nY++)
			for (nX = m_ptInterimBase.x; nX < m_ptInterimBase.x + m_szInterimBuf.cx; nX++)
				DrawCellToInterim(nX, nY);
	}
	else
	{
		for (nY = m_ptInterimBase.y; nY < m_ptInterimBase.y - nScroll; nY++)
			for (nX = m_ptInterimBase.x; nX < m_ptInterimBase.x + m_szInterimBuf.cx; nX++)
				DrawCellToInterim(nX, nY);
	}
}

