#include "diablo.h"

void town_clear_upper_buf(BYTE *pBuff)
{
	/// ASSERT: assert(gpBuffer);

#ifdef USE_ASM
	__asm {
		mov		edi, pBuff
		mov		edx, 30
		mov		ebx, 1
		xor		eax, eax
	label1:
		cmp		edi, gpBufEnd
		jb		label4
		add		edi, edx
		mov		ecx, ebx
		rep stosd
		add		edi, edx
		sub		edi, 768 + 64
		or		edx, edx
		jz		label2
		sub		edx, 2
		inc		ebx
		jmp		label1
	label2:
		mov		edx, 2
		mov		ebx, 15
	label3:
		cmp		edi, gpBufEnd
		jb		label4
		add		edi, edx
		mov		ecx, ebx
		rep stosd
		add		edi, edx
		sub		edi, 768 + 64
		dec		ebx
		add		edx, 2
		cmp		edx, 32
		jnz		label3
	label4:
		nop
	}
#else
	int i, j, k;
	BYTE *dst;

	dst = pBuff;

	for(i = 30, j = 1; i >= 0 && dst >= gpBufEnd; i -= 2, j++, dst -= 768 + 64) {
		dst += i;
		for(k = 0; k < 4 * j; k++)
			*dst++ = 0;
		dst += i;
	}
	for(i = 2, j = 15; i != 32 && dst >= gpBufEnd; i += 2, j--, dst -= 768 + 64) {
		dst += i;
		for(k = 0; k < 4 * j; k++)
			*dst++ = 0;
		dst += i;
	}
#endif
}

void town_clear_low_buf(BYTE *pBuff)
{
	/// ASSERT: assert(gpBuffer);

#ifdef USE_ASM
	__asm {
		mov		edi, pBuff
		mov		edx, 30
		mov		ebx, 1
		xor		eax, eax
	label1:
		cmp		edi, gpBufEnd
		jb		label2
		add		edi, 64
		jmp		label3
	label2:
		add		edi, edx
		mov		ecx, ebx
		rep stosd
		add		edi, edx
	label3:
		sub		edi, 768 + 64
		or		edx, edx
		jz		label4
		sub		edx, 2
		inc		ebx
		jmp		label1
	label4:
		mov		edx, 2
		mov		ebx, 15
	label5:
		cmp		edi, gpBufEnd
		jb		label6
		add		edi, 64
		jmp		label7
	label6:
		add		edi, edx
		mov		ecx, ebx
		rep stosd
		add		edi, edx
	label7:
		sub		edi, 768 + 64
		dec		ebx
		add		edx, 2
		cmp		edx, 32
		jnz		label5
	}
#else
	int i, j, k;
	BYTE *dst;

	dst = pBuff;

	for(i = 30, j = 1; i >= 0; i -= 2, j++, dst -= 768 + 64) {
		if(dst < gpBufEnd) {
			dst += i;
			for(k = 0; k < 4 * j; k++)
				*dst++ = 0;
			dst += i;
		} else {
			dst += 64;
		}
	}
	for(i = 2, j = 15; i != 32; i += 2, j--, dst -= 768 + 64) {
		if(dst < gpBufEnd) {
			dst += i;
			for(k = 0; k < 4 * j; k++)
				*dst++ = 0;
			dst += i;
		} else {
			dst += 64;
		}
	}
#endif
}

void town_special_lower(BYTE *pBuff, int nCel)
{
#if 0
	int w;
	BYTE *end;

#ifdef USE_ASM
	__asm {
		mov		ebx, pSpecialCels
		mov		eax, nCel
		shl		eax, 2
		add		ebx, eax
		mov		eax, [ebx+4]
		sub		eax, [ebx]
		mov		end, eax
		mov		esi, pSpecialCels
		add		esi, [ebx]
		mov		edi, pBuff
		mov		eax, 768 + 64
		mov		w, eax
		mov		ebx, end
		add		ebx, esi
	label1:
		mov		edx, 64
	label2:
		xor		eax, eax
		lodsb
		or		al, al
		js		label7
		sub		edx, eax
		cmp		edi, gpBufEnd
		jb		label3
		add		esi, eax
		add		edi, eax
		jmp		label6
	label3:
		mov		ecx, eax
		shr		ecx, 1
		jnb		label4
		movsb
		jecxz	label6
	label4:
		shr		ecx, 1
		jnb		label5
		movsw
		jecxz	label6
	label5:
		rep movsd
	label6:
		or		edx, edx
		jz		label8
		jmp		label2
	label7:
		neg		al
		add		edi, eax
		sub		edx, eax
		jnz		label2
	label8:
		sub		edi, w
		cmp		ebx, esi
		jnz		label1
	}
#else
	BYTE width;
	BYTE *src, *dst;
	DWORD *pFrameTable;

	pFrameTable = (DWORD *)pSpecialCels;
	src = &pSpecialCels[pFrameTable[nCel]];
	dst = pBuff;
	end = &src[pFrameTable[nCel + 1] - pFrameTable[nCel]];

	for(; src != end; dst -= 768 + 64) {
		for(w = 64; w;) {
			width = *src++;
			if(!(width & 0x80)) {
				w -= width;
				if(dst < gpBufEnd) {
					if(width & 1) {
						dst[0] = src[0];
						src++;
						dst++;
					}
					width >>= 1;
					if(width & 1) {
						dst[0] = src[0];
						dst[1] = src[1];
						src += 2;
						dst += 2;
					}
					width >>= 1;
					for(; width; width--) {
						dst[0] = src[0];
						dst[1] = src[1];
						dst[2] = src[2];
						dst[3] = src[3];
						src += 4;
						dst += 4;
					}
				} else {
					src += width;
					dst += width;
				}
			} else {
				width = -(char)width;
				dst += width;
				w -= width;
			}
		}
	}
#endif
#endif
}

void town_special_upper(BYTE *pBuff, int nCel)
{
#if 0
	int w;
	BYTE *end;

#ifdef USE_ASM
	__asm {
		mov		ebx, pSpecialCels
		mov		eax, nCel
		shl		eax, 2
		add		ebx, eax
		mov		eax, [ebx+4]
		sub		eax, [ebx]
		mov		end, eax
		mov		esi, pSpecialCels
		add		esi, [ebx]
		mov		edi, pBuff
		mov		eax, 768 + 64
		mov		w, eax
		mov		ebx, end
		add		ebx, esi
	label1:
		mov		edx, 64
	label2:
		xor		eax, eax
		lodsb
		or		al, al
		js		label6
		sub		edx, eax
		cmp		edi, gpBufEnd
		jb		label8
		mov		ecx, eax
		shr		ecx, 1
		jnb		label3
		movsb
		jecxz	label5
	label3:
		shr		ecx, 1
		jnb		label4
		movsw
		jecxz	label5
	label4:
		rep movsd
	label5:
		or		edx, edx
		jz		label7
		jmp		label2
	label6:
		neg		al
		add		edi, eax
		sub		edx, eax
		jnz		label2
	label7:
		sub		edi, w
		cmp		ebx, esi
		jnz		label1
	label8:
		nop
	}
#else
	BYTE width;
	BYTE *src, *dst;
	DWORD *pFrameTable;

	pFrameTable = (DWORD *)pSpecialCels;
	src = &pSpecialCels[pFrameTable[nCel]];
	dst = pBuff;
	end = &src[pFrameTable[nCel + 1] - pFrameTable[nCel]];

	for(; src != end; dst -= 768 + 64) {
		for(w = 64; w;) {
			width = *src++;
			if(!(width & 0x80)) {
				w -= width;
				if(dst < gpBufEnd) {
					return;
				}
				if(width & 1) {
					dst[0] = src[0];
					src++;
					dst++;
				}
				width >>= 1;
				if(width & 1) {
					dst[0] = src[0];
					dst[1] = src[1];
					src += 2;
					dst += 2;
				}
				width >>= 1;
				for(; width; width--) {
					dst[0] = src[0];
					dst[1] = src[1];
					dst[2] = src[2];
					dst[3] = src[3];
					src += 4;
					dst += 4;
				}
			} else {
				width = -(char)width;
				dst += width;
				w -= width;
			}
		}
	}
#endif
#endif
}

void town_draw_clipped_e_flag(BYTE *pBuff, int x, int y, int sx, int sy)
{
	int i;
	BYTE *dst;
	MICROS *pMap;

	dst = pBuff;
	pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];

	for(i = 0; i < 12; i += 2) {
		level_cel_block = pMap->mt[i];
		if(level_cel_block != 0) {
			drawLowerScreen(dst);
		}
		level_cel_block = pMap->mt[i + 1];
		if(level_cel_block != 0) {
			drawLowerScreen(dst + 32);
		}
		dst -= 768 * 32;
	}

	town_draw_clipped_town(pBuff, x, y, sx, sy, 0);
}

void town_draw_clipped_town(BYTE *pBuff, int x, int y, int sx, int sy, int some_flag)
{
	int mi, px, py;
	char bv;

	/// ASSERT: assert(gpBuffer);

	pBuff = &gpBuffer[sx + PitchTbl[sy]];

	if(dItem[x][y] != 0) {
		bv = dItem[x][y] - 1;
		px = sx - item[bv]._iAnimWidth2;
		if(bv == pcursitem) {
			CelDrawHdrClrHL(181, px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, 8);
		}
		Cel2DrawHdrOnly(px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, 8);
	}
	if(dFlags[x][y] & 0x10) {
		mi = -(dMonster[x][y - 1] + 1);
		px = sx - towner[mi]._tAnimWidth2;
		if(mi == pcursmonst) {
			CelDrawHdrClrHL(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8);
		}
		Cel2DrawHdrOnly(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8);
	}
	if(dMonster[x][y] > 0) {
		mi = dMonster[x][y] - 1;
		px = sx - towner[mi]._tAnimWidth2;
		if(mi == pcursmonst) {
			CelDrawHdrClrHL(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8);
		}
		Cel2DrawHdrOnly(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8);
	}
	if(dFlags[x][y] & 0x20) {
		bv = -(dPlayer[x][y - 1] + 1);
		px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2;
		py = sy + plr[bv]._pyoff;
		if(bv == pcursplr) {
			Cl2DecodeClrHL(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8);
		}
		Cl2DecodeFrm4(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8);
		if(some_flag && plr[bv]._peflag) {
			town_draw_clipped_e_flag(pBuff - 64, x - 1, y + 1, sx - 64, sy);
		}
	}
	if(dFlags[x][y] & 4) {
		DrawDeadPlayer(x, y, sx, sy, 0, 8, 1);
	}
	if(dPlayer[x][y] > 0) {
		bv = dPlayer[x][y] - 1;
		px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2;
		py = sy + plr[bv]._pyoff;
		if(bv == pcursplr) {
			Cl2DecodeClrHL(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8);
		}
		Cl2DecodeFrm4(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8);
		if(some_flag && plr[bv]._peflag) {
			town_draw_clipped_e_flag(pBuff - 64, x - 1, y + 1, sx - 64, sy);
		}
	}
	if(dFlags[x][y] & 1) {
		DrawClippedMissile(x, y, sx, sy, 0, 8, 0);
	}
	if(dSpecial[x][y] != 0) {
		town_special_lower(pBuff, dSpecial[x][y]);
	}
}

void town_draw_lower(int x, int y, int sx, int sy, int a5, int some_flag)
{
	int i, j;
	BYTE *dst;
	MICROS *pMap;

	/// ASSERT: assert(gpBuffer);

	if(some_flag) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx + 32 + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 1; i < 17; i += 2) {
					level_cel_block = pMap->mt[i];
					if(level_cel_block != 0) {
						drawLowerScreen(dst);
					}
					dst -= 768 * 32;
				}
				town_draw_clipped_town(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 0);
			} else {
				town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
		x++;
		y--;
		sx += 64;
	}

	for(j = 0; j < a5 - some_flag; j++) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 16; i += 2) {
					level_cel_block = pMap->mt[i];
					if(level_cel_block != 0) {
						drawLowerScreen(dst);
					}
					level_cel_block = pMap->mt[i + 1];
					if(level_cel_block != 0) {
						drawLowerScreen(dst + 32);
					}
					dst -= 768 * 32;
				}
				town_draw_clipped_town(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 1);
			} else {
				town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
		x++;
		y--;
		sx += 64;
	}

	if(some_flag) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 16; i += 2) {
					level_cel_block = pMap->mt[i];
					if(level_cel_block != 0) {
						drawLowerScreen(dst);
					}
					dst -= 768 * 32;
				}
				town_draw_clipped_town(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 0);
			} else {
				town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
	}
}

void town_draw_clipped_e_flag_2(BYTE *pBuff, int x, int y, int a4, int a5, int sx, int sy)
{
	int i;
	BYTE *dst;
	MICROS *pMap;

	if(a4 == 0) {
		dst = pBuff;
	} else {
		dst = &pBuff[768 * 32 * a4];
	}

	pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];

	for(i = 0; i < 6; i++) {
		if(a4 <= i) {
			level_cel_block = pMap->mt[2 * i + 2];
			if(level_cel_block != 0) {
				drawLowerScreen(dst);
			}
			level_cel_block = pMap->mt[2 * i + 3];
			if(level_cel_block != 0) {
				drawLowerScreen(dst + 32);
			}
		}
		dst -= 768 * 32;
	}

	if(a5 < 8) {
		town_draw_clipped_town_2(pBuff, x, y, a4, a5, sx, sy, 0);
	}
}

void town_draw_clipped_town_2(BYTE *pBuff, int x, int y, int a4, int a5, int sx, int sy, int some_flag)
{
	int mi, px, py;
	char bv;

	if(dItem[x][y] != 0) {
		bv = dItem[x][y] - 1;
		px = sx - item[bv]._iAnimWidth2;
		if(bv == pcursitem) {
			CelDrawHdrClrHL(181, px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, a5, 8);
		}
		Cel2DrawHdrOnly(px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, a5, 8);
	}
	if(dFlags[x][y] & 0x10) {
		mi = -(dMonster[x][y - 1] + 1);
		px = sx - towner[mi]._tAnimWidth2;
		if(mi == pcursmonst) {
			CelDrawHdrClrHL(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, a5, 8);
		}
		Cel2DrawHdrOnly(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, a5, 8);
	}
	if(dMonster[x][y] > 0) {
		mi = dMonster[x][y] - 1;
		px = sx - towner[mi]._tAnimWidth2;
		if(mi == pcursmonst) {
			CelDrawHdrClrHL(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, a5, 8);
		}
		Cel2DrawHdrOnly(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, a5, 8);
	}
	if(dFlags[x][y] & 0x20) {
		bv = -(dPlayer[x][y - 1] + 1);
		px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2;
		py = sy + plr[bv]._pyoff;
		if(bv == pcursplr) {
			Cl2DecodeClrHL(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, a5, 8);
		}
		Cl2DecodeFrm4(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, a5, 8);
		if(some_flag && plr[bv]._peflag) {
			town_draw_clipped_e_flag_2(pBuff - 64, x - 1, y + 1, a4, a5, sx - 64, sy);
		}
	}
	if(dFlags[x][y] & 4) {
		DrawDeadPlayer(x, y, sx, sy, a5, 8, 1);
	}
	if(dPlayer[x][y] > 0) {
		bv = dPlayer[x][y] - 1;
		px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2;
		py = sy + plr[bv]._pyoff;
		if(bv == pcursplr) {
			Cl2DecodeClrHL(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, a5, 8);
		}
		Cl2DecodeFrm4(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, a5, 8);
		if(some_flag && plr[bv]._peflag) {
			town_draw_clipped_e_flag_2(pBuff - 64, x - 1, y + 1, a4, a5, sx - 64, sy);
		}
	}
	if(dFlags[x][y] & 1) {
		DrawClippedMissile(x, y, sx, sy, a5, 8, 0);
	}
	if(dSpecial[x][y] != 0) {
		town_special_lower(&pBuff[PitchTbl[16 * a5]], dSpecial[x][y]);
	}
}

void town_draw_lower_2(int x, int y, int sx, int sy, int a5, int a6, int some_flag)
{
	int i, j, dir;
	BYTE *dst;
	MICROS *pMap;

	/// ASSERT: assert(gpBuffer);

	dir = 2 * a6 + 2;

	if(some_flag) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx - (768 * 32 - 32) + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 7; i++) {
					if(a6 <= i) {
						level_cel_block = pMap->mt[2 * i + 3];
						if(level_cel_block != 0) {
							drawLowerScreen(dst);
						}
					}
					dst -= 768 * 32;
				}
				if(dir < 8) {
					town_draw_clipped_town_2(&gpBuffer[sx + PitchTbl[sy]], x, y, a6, dir, sx, sy, 0);
				}
			} else {
				town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
		x++;
		y--;
		sx += 64;
	}

	for(j = 0; j < a5 - some_flag; j++) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx - 768 * 32 + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 7; i++) {
					if(a6 <= i) {
						level_cel_block = pMap->mt[2 * i + 2];
						if(level_cel_block != 0) {
							drawLowerScreen(dst);
						}
						level_cel_block = pMap->mt[2 * i + 3];
						if(level_cel_block != 0) {
							drawLowerScreen(dst + 32);
						}
					}
					dst -= 768 * 32;
				}
				if(dir < 8) {
					town_draw_clipped_town_2(&gpBuffer[sx + PitchTbl[sy] - 768 * 16 * dir], x, y, a6, dir, sx, sy, 1);
				}
			} else {
				town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
		x++;
		y--;
		sx += 64;
	}

	if(some_flag) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx - 768 * 32 + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 7; i++) {
					if(a6 <= i) {
						level_cel_block = pMap->mt[2 * i + 2];
						if(level_cel_block != 0) {
							drawLowerScreen(dst);
						}
					}
					dst -= 768 * 32;
				}
				if(dir < 8) {
					town_draw_clipped_town_2(&gpBuffer[sx + PitchTbl[sy]], x, y, a6, dir, sx, sy, 0);
				}
			} else {
				town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
	}
}

void town_draw_e_flag(BYTE *pBuff, int x, int y, int a4, int dir, int sx, int sy)
{
	int i;
	BYTE *dst;
	MICROS *pMap;

	dst = pBuff;
	pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];

	for(i = 0; i < 7; i++) {
		if(a4 >= i) {
			level_cel_block = pMap->mt[2 * i];
			if(level_cel_block != 0) {
				drawUpperScreen(dst);
			}
			level_cel_block = pMap->mt[2 * i + 1];
			if(level_cel_block != 0) {
				drawUpperScreen(dst + 32);
			}
		}
		dst -= 768 * 32;
	}

	town_draw_town_all(pBuff, x, y, a4, dir, sx, sy, 0);
}

void town_draw_town_all(BYTE *pBuff, int x, int y, int a4, int dir, int sx, int sy, int some_flag)
{
	int mi, px, py;
	char bv;

	if(dItem[x][y] != 0) {
		bv = dItem[x][y] - 1;
		px = sx - item[bv]._iAnimWidth2;
		if(bv == pcursitem) {
			CelDecodeClr(181, px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, dir);
		}
		/// ASSERT: assert(item[bv]._iAnimData);
		CelDrawHdrOnly(px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, dir);
	}
	if(dFlags[x][y] & 0x10) {
		mi = -(dMonster[x][y - 1] + 1);
		px = sx - towner[mi]._tAnimWidth2;
		if(mi == pcursmonst) {
			CelDecodeClr(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, dir);
		}
		/// ASSERT: assert(towner[mi]._tAnimData);
		CelDrawHdrOnly(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, dir);
	}
	if(dMonster[x][y] > 0) {
		mi = dMonster[x][y] - 1;
		px = sx - towner[mi]._tAnimWidth2;
		if(mi == pcursmonst) {
			CelDecodeClr(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, dir);
		}
		/// ASSERT: assert(towner[mi]._tAnimData);
		CelDrawHdrOnly(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, dir);
	}
	if(dFlags[x][y] & 0x20) {
		bv = -(dPlayer[x][y - 1] + 1);
		px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2;
		py = sy + plr[bv]._pyoff;
		if(bv == pcursplr) {
			Cl2DecodeFrm2(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, dir);
		}
		/// ASSERT: assert(plr[bv]._pAnimData);
		Cl2DecodeFrm1(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, dir);
		if(some_flag && plr[bv]._peflag) {
			town_draw_e_flag(pBuff - 64, x - 1, y + 1, a4, dir, sx - 64, sy);
		}
	}
	if(dFlags[x][y] & 4) {
		DrawDeadPlayer(x, y, sx, sy, 0, dir, 0);
	}
	if(dPlayer[x][y] > 0) {
		bv = dPlayer[x][y] - 1;
		px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2;
		py = sy + plr[bv]._pyoff;
		if(bv == pcursplr) {
			Cl2DecodeFrm2(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, dir);
		}
		/// ASSERT: assert(plr[bv]._pAnimData);
		Cl2DecodeFrm1(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, dir);
		if(some_flag && plr[bv]._peflag) {
			town_draw_e_flag(pBuff - 64, x - 1, y + 1, a4, dir, sx - 64, sy);
		}
	}
	if(dFlags[x][y] & 1) {
		DrawMissile(x, y, sx, sy, 0, dir, 0);
	}
	if(dSpecial[x][y] != 0) {
		town_special_upper(pBuff, dSpecial[x][y]);
	}
}

void town_draw_upper(int x, int y, int sx, int sy, int a5, int a6, int some_flag)
{
	int i, j, dir;
	BYTE *dst;
	MICROS *pMap;

	/// ASSERT: assert(gpBuffer);

	dir = 2 * a6 + 2;
	if(dir > 8) {
		dir = 8;
	}

	if(some_flag) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx + 32 + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 7; i++) {
					if(a6 >= i) {
						level_cel_block = pMap->mt[2 * i + 1];
						if(level_cel_block != 0) {
							drawUpperScreen(dst);
						}
					}
					dst -= 768 * 32;
				}
				town_draw_town_all(&gpBuffer[sx + PitchTbl[sy]], x, y, a6, dir, sx, sy, 0);
			} else {
				town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
		x++;
		y--;
		sx += 64;
	}

	for(j = 0; j < a5 - some_flag; j++) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 7; i++) {
					if(a6 >= i) {
						level_cel_block = pMap->mt[2 * i];
						if(level_cel_block != 0) {
							drawUpperScreen(dst);
						}
						level_cel_block = pMap->mt[2 * i + 1];
						if(level_cel_block != 0) {
							drawUpperScreen(dst + 32);
						}
					}
					dst -= 768 * 32;
				}
				town_draw_town_all(&gpBuffer[sx + PitchTbl[sy]], x, y, a6, dir, sx, sy, 1);
			} else {
				town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
		x++;
		y--;
		sx += 64;
	}

	if(some_flag) {
		if(y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
			level_cel_block = dPiece[x][y];
			if(level_cel_block != 0) {
				dst = &gpBuffer[sx + PitchTbl[sy]];
				pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
				for(i = 0; i < 7; i++) {
					if(a6 >= i) {
						level_cel_block = pMap->mt[2 * i];
						if(level_cel_block != 0) {
							drawUpperScreen(dst);
						}
					}
					dst -= 768 * 32;
				}
				town_draw_town_all(&gpBuffer[sx + PitchTbl[sy]], x, y, a6, dir, sx, sy, 0);
			} else {
				town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]);
			}
		} else {
			town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]);
		}
	}
}

void T_DrawGame(int x, int y)
{
	int i, sx, sy, chunks, blocks;

	ViewDX = 640;
	ViewDY = 352;
	ViewBX = 10;
	ViewBY = 11;

	sx = ScrollInfo._sxoff + 64;
	sy = ScrollInfo._syoff + 175;
	x -= 10;
	y--;
	chunks = 10;
	blocks = 5;

	if(chrflag || questlog) {
		x += 2;
		y -= 2;
		sx += 288;
		chunks = 6;
	}
	if(invflag || sbookflag) {
		x += 2;
		y -= 2;
		sx -= 32;
		chunks = 6;
	}

	switch(ScrollInfo._sdir) {
	case 0:
		break;
	case 1:
		sy -= 32;
		x--;
		y--;
		blocks++;
		break;
	case 2:
		sy -= 32;
		x--;
		y--;
		chunks++;
		blocks++;
		break;
	case 3:
		chunks++;
		break;
	case 4:
		chunks++;
		blocks++;
		break;
	case 5:
		blocks++;
		break;
	case 6:
		sx -= 64;
		x--;
		y++;
		chunks++;
		blocks++;
		break;
	case 7:
		sx -= 64;
		x--;
		y++;
		chunks++;
		break;
	case 8:
		sx -= 64;
		sy -= 32;
		x -= 2;
		chunks++;
		blocks++;
		break;
	}

	/// ASSERT: assert(gpBuffer);
	gpBufEnd = &gpBuffer[PitchTbl[160]];
	for(i = 0; i < 7; i++) {
		town_draw_upper(x, y, sx, sy, chunks, i, 0);
		y++;
		sx -= 32;
		sy += 16;
		town_draw_upper(x, y, sx, sy, chunks, i, 1);
		x++;
		sx += 32;
		sy += 16;
	}
	/// ASSERT: assert(gpBuffer);
	gpBufEnd = &gpBuffer[PitchTbl[512]];
	for(i = 0; i < blocks; i++) {
		town_draw_lower(x, y, sx, sy, chunks, 0);
		y++;
		sx -= 32;
		sy += 16;
		town_draw_lower(x, y, sx, sy, chunks, 1);
		x++;
		sx += 32;
		sy += 16;
	}
	for(i = 0; i < 7; i++) {
		town_draw_lower_2(x, y, sx, sy, chunks, i, 0);
		y++;
		sx -= 32;
		sy += 16;
		town_draw_lower_2(x, y, sx, sy, chunks, i, 1);
		x++;
		sx += 32;
		sy += 16;
	}
}

void T_DrawZoom(int x, int y)
{
	int i, sx, sy, chunks, blocks;
	int wdt, nSrcOff, nDstOff;

	ViewDX = 384;
	ViewDY = 192;
	ViewBX = 6;
	ViewBY = 6;

	sx = ScrollInfo._sxoff + 64;
	sy = ScrollInfo._syoff + 143;
	x -= 6;
	y--;
	chunks = 6;
	blocks = 0;

	switch(ScrollInfo._sdir) {
	case 0:
		break;
	case 1:
		sy -= 32;
		x--;
		y--;
		blocks++;
		break;
	case 2:
		sy -= 32;
		x--;
		y--;
		chunks++;
		blocks++;
		break;
	case 3:
		chunks++;
		break;
	case 4:
		chunks++;
		blocks++;
		break;
	case 5:
		blocks++;
		break;
	case 6:
		sx -= 64;
		x--;
		y++;
		chunks++;
		blocks++;
		break;
	case 7:
		sx -= 64;
		x--;
		y++;
		chunks++;
		break;
	case 8:
		sx -= 64;
		sy -= 32;
		x -= 2;
		chunks++;
		blocks++;
		break;
	}

	/// ASSERT: assert(gpBuffer);
	gpBufEnd = &gpBuffer[PitchTbl[143]];
	for(i = 0; i < 7; i++) {
		town_draw_upper(x, y, sx, sy, chunks, i, 0);
		y++;
		sx -= 32;
		sy += 16;
		town_draw_upper(x, y, sx, sy, chunks, i, 1);
		x++;
		sx += 32;
		sy += 16;
	}
	/// ASSERT: assert(gpBuffer);
	gpBufEnd = &gpBuffer[PitchTbl[320]];
	for(i = 0; i < blocks; i++) {
		town_draw_lower(x, y, sx, sy, chunks, 0);
		y++;
		sx -= 32;
		sy += 16;
		town_draw_lower(x, y, sx, sy, chunks, 1);
		x++;
		sx += 32;
		sy += 16;
	}
	for(i = 0; i < 7; i++) {
		town_draw_lower_2(x, y, sx, sy, chunks, i, 0);
		y++;
		sx -= 32;
		sy += 16;
		town_draw_lower_2(x, y, sx, sy, chunks, i, 1);
		x++;
		sx += 32;
		sy += 16;
	}

	if(chrflag || questlog) {
		nSrcOff = SCREENXY(112, 159);
		nDstOff = SCREENXY(320, 350);
		wdt = 160;
	} else if(invflag || sbookflag) {
		nSrcOff = SCREENXY(112, 159);
		nDstOff = SCREENXY(0, 350);
		wdt = 160;
	} else {
		nSrcOff = SCREENXY(32, 159);
		nDstOff = SCREENXY(0, 350);
		wdt = 320;
	}

	/// ASSERT: assert(gpBuffer);

#ifdef USE_ASM
	__asm {
		mov		esi, gpBuffer
		mov		edx, nDstOff
		mov		edi, esi
		mov		ecx, nSrcOff
		add		edi, edx
		add		esi, ecx
		mov		ebx, edi
		add		ebx, 768
		mov		edx, 176
	label1:
		mov		ecx, wdt
	label2:
		mov		al, [esi]
		inc		esi
		mov		ah, al
		mov		[edi], ax
		mov		[ebx], ax
		add		edi, 2
		add		ebx, 2
		dec		ecx
		jnz		label2
		mov		eax, 768
		add		eax, wdt
		sub		esi, eax
		add		eax, eax
		sub		ebx, eax
		sub		edi, eax
		dec		edx
		jnz		label1
	}
#else
	int hgt;
	BYTE *src, *dst1, *dst2;

	src = &gpBuffer[nSrcOff];
	dst1 = &gpBuffer[nDstOff];
	dst2 = &gpBuffer[nDstOff + 768];

	for(hgt = 176; hgt != 0; hgt--, src -= 768 + wdt, dst1 -= 2 * (768 + wdt), dst2 -= 2 * (768 + wdt)) {
		for(i = wdt; i != 0; i--) {
			*dst1++ = *src;
			*dst1++ = *src;
			*dst2++ = *src;
			*dst2++ = *src;
			src++;
		}
	}
#endif
}

void T_DrawView(int StartX, int StartY)
{
	light_table_index = 0;
	cel_transparency_active = 0;
	if ( zoomflag )
		T_DrawGame(StartX, StartY);
	else
		T_DrawZoom(StartX, StartY);
	if ( automapflag )
		DrawAutomap();
	if ( stextflag && !qtextflag )
		DrawSText();
	if ( invflag )
	{
		DrawInv();
	}
	else if ( sbookflag )
	{
		DrawSpellBook();
	}
	DrawDurIcon();
	if ( chrflag )
	{
		DrawChr();
	}
	else if ( questlog )
	{
		DrawQuestLog();
	}
	else if ( plr[myplr]._pStatPts && !spselflag )
	{
		DrawLevelUpIcon();
	}
	if ( uitemflag )
		DrawUniqueInfo();
	if ( qtextflag )
		DrawQText();
	if ( spselflag )
		DrawSpellList();
	if ( dropGoldFlag )
		DrawGoldSplit(dropGoldValue);
	if ( helpflag )
		DrawHelp();
	if ( msgflag )
		DrawDiabloMsg();
	if ( PauseMode && !deathflag )
		gmenu_draw_pause();
	DrawPlrMsg();
	gmenu_draw();
	doom_draw();
	DrawInfoBox();
	DrawLifeFlask();
	DrawManaFlask();
}

void SetTownMicros()
{
	int i, x, y, lv;
	WORD *pPiece;
	MICROS *pMap;

	for(y = 0; y < MAXDUNY; y++) {
		for(x = 0; x < MAXDUNX; x++) {
			lv = dPiece[x][y];
			pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
			if(lv != 0) {
				lv--;
				pPiece = (WORD *)&pLevelPieces[32 * lv];
				for(i = 0; i < 16; i++) {
					pMap->mt[i] = pPiece[(i & 1) + 16 - 2 - (i & 0xE)];
				}
			} else {
				for(i = 0; i < 16; i++) {
					pMap->mt[i] = 0;
				}
			}
		}
	}

	if(zoomflag) {
		ViewDX = 640;
		ViewDY = 352;
		ViewBX = 10;
		ViewBY = 11;
	} else {
		ViewDX = 384;
		ViewDY = 224;
		ViewBX = 6;
		ViewBY = 7;
	}
}

void T_FillSector(unsigned char *P3Tiles, unsigned char *pSector, int xi, int yi, int w, int h)
{
	int i, j, xx, yy;
	long v1, v2, v3, v4, ii;

	ii = 4;
	yy = yi;
	for(j = 0; j < h; j++) {
		xx = xi;
		for(i = 0; i < w; i++) {
#ifdef USE_ASM
			__asm {
				mov		esi, pSector
				mov		eax, ii
				add		esi, eax
				xor		eax, eax
				lodsw
				or		eax, eax
				jz		label1
				dec		eax
				mov		esi, P3Tiles
				shl		eax, 3
				add		esi, eax
				xor		eax, eax
				lodsw
				inc		eax
				mov		v1, eax
				lodsw
				inc		eax
				mov		v2, eax
				lodsw
				inc		eax
				mov		v3, eax
				lodsw
				inc		eax
				mov		v4, eax
				jmp		label2
			label1:
				mov		v1, eax
				mov		v2, eax
				mov		v3, eax
				mov		v4, eax
			label2:
				nop
			}
#else
			WORD *Map;

			Map = (WORD *)&pSector[ii];
			if(*Map != 0) {
				v1 = ((WORD *)&P3Tiles[(*Map - 1) << 3])[0] + 1;
				v2 = ((WORD *)&P3Tiles[(*Map - 1) << 3])[1] + 1;
				v3 = ((WORD *)&P3Tiles[(*Map - 1) << 3])[2] + 1;
				v4 = ((WORD *)&P3Tiles[(*Map - 1) << 3])[3] + 1;
			} else {
				v1 = 0;
				v2 = 0;
				v3 = 0;
				v4 = 0;
			}
#endif
			dPiece[xx][yy] = v1;
			dPiece[xx + 1][yy] = v2;
			dPiece[xx][yy + 1] = v3;
			dPiece[xx + 1][yy + 1] = v4;
			xx += 2;
			ii += 2;
		}
		yy += 2;
	}
}

void T_FillTile(unsigned char *P3Tiles, int xx, int yy, int t)
{
	long v1, v2, v3, v4;

#ifdef USE_ASM
	__asm {
		mov		eax, t
		dec		eax
		mov		esi, P3Tiles
		shl		eax, 3
		add		esi, eax
		xor		eax, eax
		lodsw
		inc		eax
		mov		v1, eax
		lodsw
		inc		eax
		mov		v2, eax
		lodsw
		inc		eax
		mov		v3, eax
		lodsw
		inc		eax
		mov		v4, eax
		jmp		label1
		mov		v1, eax
		mov		v2, eax
		mov		v3, eax
		mov		v4, eax
	label1:
		nop
	}
#else
	v1 = ((WORD *)&P3Tiles[(t - 1) << 3])[0] + 1;
	v2 = ((WORD *)&P3Tiles[(t - 1) << 3])[1] + 1;
	v3 = ((WORD *)&P3Tiles[(t - 1) << 3])[2] + 1;
	v4 = ((WORD *)&P3Tiles[(t - 1) << 3])[3] + 1;
#endif

	dPiece[xx][yy] = v1;
	dPiece[xx + 1][yy] = v2;
	dPiece[xx][yy + 1] = v3;
	dPiece[xx + 1][yy + 1] = v4;
}

void T_Pass3()
{
	int xx, yy, x;
	unsigned char *P3Tiles, *pSector;

	for(yy = 0; yy < MAXDUNY; yy += 2) {
		for(xx = 0; xx < MAXDUNX; xx += 2) {
			dPiece[xx][yy] = 0;
			dPiece[xx + 1][yy] = 0;
			dPiece[xx][yy + 1] = 0;
			dPiece[xx + 1][yy + 1] = 0;
		}
	}

	P3Tiles = DiabLoad("Levels\\TownData\\Town.TIL", NULL, 'TOWN');
	pSector = DiabLoad("Levels\\TownData\\Sector1s.DUN", NULL, 'TOWN');
	T_FillSector(P3Tiles, pSector, 46, 46, 25, 25);
	mem_free_dbg(pSector);
	pSector = DiabLoad("Levels\\TownData\\Sector2s.DUN", NULL, 'TOWN');
	T_FillSector(P3Tiles, pSector, 46, 0, 25, 23);
	mem_free_dbg(pSector);
	pSector = DiabLoad("Levels\\TownData\\Sector3s.DUN", NULL, 'TOWN');
	T_FillSector(P3Tiles, pSector, 0, 46, 23, 25);
	mem_free_dbg(pSector);
	pSector = DiabLoad("Levels\\TownData\\Sector4s.DUN", NULL, 'TOWN');
	T_FillSector(P3Tiles, pSector, 0, 0, 23, 23);
	mem_free_dbg(pSector);

	if(gbMaxPlayers == 1) {
		if(!(plr[myplr].pTownWarps & 1)) {
			T_FillTile(P3Tiles, 48, 20, 320);
		}
		if(!(plr[myplr].pTownWarps & 2)) {
			T_FillTile(P3Tiles, 16, 68, 332);
			T_FillTile(P3Tiles, 16, 70, 331);
		}
		if(!(plr[myplr].pTownWarps & 4)) {
			for(x = 36; x < 46; x++) {
				T_FillTile(P3Tiles, x, 78, random(0, 4) + 1);
			}
		}
	}

	if(quests[13]._qactive != 3 && quests[13]._qactive) {
		T_FillTile(P3Tiles, 60, 70, 342);
	} else {
		T_FillTile(P3Tiles, 60, 70, 71);
	}

	mem_free_dbg(P3Tiles);
}

void CreateTown(int entry)
{
	int x, y;

	dminx = 10;
	dminy = 10;
	dmaxx = 84;
	dmaxy = 84;

	if(entry == 0) {
		ViewX = 75;
		ViewY = 68;
	} else if(entry == 1) {
		ViewX = 25;
		ViewY = 31;
	} else if(entry == 7) {
		if(TWarpFrom == 5) {
			ViewX = 49;
			ViewY = 22;
		}
		if(TWarpFrom == 9) {
			ViewX = 18;
			ViewY = 69;
		}
		if(TWarpFrom == 13) {
			ViewX = 41;
			ViewY = 81;
		}
	}

	T_Pass3();
	memset(dLight, 0, sizeof(dLight));
	memset(dFlags, 0, sizeof(dFlags));
	memset(dPlayer, 0, sizeof(dPlayer));
	memset(dMonster, 0, sizeof(dMonster));
	memset(dObject, 0, sizeof(dObject));
	memset(dItem, 0, sizeof(dItem));
	memset(dSpecial, 0, sizeof(dSpecial));

	for(y = 0; y < MAXDUNY; y++) {
		for(x = 0; x < MAXDUNX; x++) {
			if(dPiece[x][y] == 360) {
				dSpecial[x][y] = 1;
			} else if(dPiece[x][y] == 358) {
				dSpecial[x][y] = 2;
			} else if(dPiece[x][y] == 129) {
				dSpecial[x][y] = 6;
			} else if(dPiece[x][y] == 130) {
				dSpecial[x][y] = 7;
			} else if(dPiece[x][y] == 128) {
				dSpecial[x][y] = 8;
			} else if(dPiece[x][y] == 117) {
				dSpecial[x][y] = 9;
			} else if(dPiece[x][y] == 157) {
				dSpecial[x][y] = 10;
			} else if(dPiece[x][y] == 158) {
				dSpecial[x][y] = 11;
			} else if(dPiece[x][y] == 156) {
				dSpecial[x][y] = 12;
			} else if(dPiece[x][y] == 162) {
				dSpecial[x][y] = 13;
			} else if(dPiece[x][y] == 160) {
				dSpecial[x][y] = 14;
			} else if(dPiece[x][y] == 214) {
				dSpecial[x][y] = 15;
			} else if(dPiece[x][y] == 212) {
				dSpecial[x][y] = 16;
			} else if(dPiece[x][y] == 217) {
				dSpecial[x][y] = 17;
			} else if(dPiece[x][y] == 216) {
				dSpecial[x][y] = 18;
			}
		}
	}

	SetTownMicros();
}
