#ifndef screenBufferSeg
#define screenBufferSeg 0B800h
#endif

:byte _cursorX=0,_cursorY=0;
//:byte _screenCols=80,_screenRows=25;
//#define _screenRows 25
//#define _screenCols 80

#define _screenRows realRows
#define _screenCols realCols
:byte _screenMode=3;

:void fastcall GOTOXY(DL,DH)
{
	BH = 0;
	AH = 2;
	$INT 0x10
}

// VWRITEXY(char c,byte X,byte Y);
:void fastcall VWRITEXY(BL,BH,AL)
{
	$push ds
	AX = AL * 80;
	AX += BH;
	CL = BL;
	BX = AX*2;
	DS = screenBufferSeg;
	DSBYTE[BX] = CL;
	$pop ds
}

// VWRITEXYA(char c,byte X,byte Y,byte arrt);
:void fastcall VWRITEXYA(BL,BH,AL,AH)
{
	$push ds
	$push ax
	AX = AL * 80;
	AX += BH;
	CL = BL;
	BX = AX * 2;
	DS = screenBufferSeg;
	$pop ax
	AL = CL;
	DSBYTE[BX+1] = AH;
	IF(AL != 0)	DSBYTE[BX] = AL;
	$pop ds
}


:void fastcall VWRITEXYN(BL,BH,AL,CL)
{
	CH = 0;
	LOOPNZ(CX) 
	{	
		$push ax,bx,cx
		VWRITEXY(BL,BH + CL - 1,AL);
		$pop cx,bx,ax
	}
}

:void fastcall VWRITEXYNA(BL,BH,AL,CL,AH)
{
	CH = 0;
	LOOPNZ(CX) 
	{	
		$push ax,bx,cx
		VWRITEXYA(BL,BH + CL - 1,AL,AH);
		$pop cx,bx,ax
	}
}

:void fastcall VWRITENA1(BL,CL,AH)
{
	VWRITEXYNA(BL,CSBYTE[#_cursorX],CSBYTE[#_cursorY],CL,AH);
}

#define VWriteXY VWRITEXY

// VWRITESTRXY(char* string,byte X,byte Y);
:void fastcall VWRITESTRXY(SI,BL,AL)
{
	$push es
	AX = AL * 80;
	BH = 0;
	AX += BX;
	DI = AX*2;
	ES = screenBufferSeg;

	$lodsb
	while(AL != 0)
	{
		$stosb
		DI++;
		$lodsb
	}
	$pop es
}


:void fastcall VWriteStrXY(SI,BL,AL)
{
	$push si,di
	@VWRITESTRXY(SI,BL,AL);
	$pop di,si
}

// VWRITESTRXYN(char* string,byte X,byte Y,int n);
:void fastcall VWRITESTRXYN(SI,BL,AL,CX)
{
	IF(CX == 0)RETURN;

	$push es
	$push cx
	AX = AL * 80;
	BH = 0;
	AX += BX;
	DI = AX*2;
	ES = screenBufferSeg;
	$pop cx

	loop(CX)
	{
		$lodsb
		$stosb
		DI++;
	}
	$pop es
}

// VWRITESTRXYN(char* string,byte X,byte Y,int n,byte attr);
:void fastcall VWRITESTRXYNA(SI,BL,AL,CX,AH)
{
	IF(CX == 0)RETURN;

	$push es
	$push ax,cx
	AX = AL * 80;
	BH = 0;
	AX += BX;
	DI = AX*2;
	ES = screenBufferSeg;
	$pop cx,ax

	loop(CX)
	{
		$lodsb
		$stosw
	}
	$pop es
}

:void fastcall VWriteStrXYN(SI,BL,AL,CX)
{
	$push si,di
	@VWRITESTRXYN(SI,BL,AL,CX);
	$pop di,si
}


:void fastcall VGOTOXY(AL,AH)
{
	CSBYTE[#_cursorX] = AL;
	CSBYTE[#_cursorY] = AH;
}

:void fastcall VBACKXY1()
{
	CSBYTE[#_cursorX]--;
}

:void fastcall VNEXTLINE()
{
	CSBYTE[#_cursorX] = 0;
	CSBYTE[#_cursorY]++;
}

:void fastcall VADJUSTXY()
{
	GETXY();
	VGOTOXY();
}

:void fastcall BADJUSTXY()
{
	GOTOXY(CSBYTE[#_cursorX],CSBYTE[#_cursorY]);
}

:void fastcall VWRITE1(BL)
{
	$push ds
	DS = CS;
	VWRITEXY(BL,_cursorX,_cursorY);
	IF(_cursorX+1 >= _screenCols)
	{
		_cursorX = 0;
		_cursorY++;
	}
	ELSE
	{
		_cursorX++;
	}
	$pop ds
}


:void fastcall VWRITEA(BL,AH)
{
	$push ds
	DS = CS;
	VWRITEXYA(BL,_cursorX,_cursorY,AH);
	IF(_cursorX+1 >= _screenCols)
	{
		_cursorX = 0;
		_cursorY++;
	}
	ELSE
	{
		_cursorX++;
	}
	$pop ds
}

:void fastcall VWRITESTRN(SI,CX)
{
	$push cx
	VWRITESTRXYN(SI,CSBYTE[#_cursorX],CSBYTE[#_cursorY],CX);
	$pop cx

	$push ds
	DS = CS;
	_cursorX += CX;
	WHILE(_cursorX+1 >= _screenCols)
	{
		_cursorX -= 80;
		_cursorY++;
	}
	$pop ds
}


:void fastcall VWRITESTRNA(SI,CX,AH)
{
	$push cx
	VWRITESTRXYNA(SI,CSBYTE[#_cursorX],CSBYTE[#_cursorY],CX,AH);
	$pop cx

	$push ds
	DS = CS;
	_cursorX += CX;
	WHILE(_cursorX+1 >= _screenCols)
	{
		_cursorX -= 80;
		_cursorY++;
	}
	$pop ds
}

// VWRITESTR(char* string);
:void fastcall VWRITESTR(SI)
{
	CX = STRLEN(SI);
	VWRITESTRN(SI,CX);
}

:void fastcall VWRITESTRA(SI,AH)
{
	$push ax
	CX = STRLEN(SI);
	$pop ax
	VWRITESTRNA(SI,CX,AH);
}

:void fastcall VWRITESTRXYA(SI,AL,AH,BH)
{
	VGOTOXY(AL,AH);
	VWRITESTRA(SI,BH);
}

:void fastcall VWRITESTRALN(SI,BH)
{
	VWRITESTRA(SI,BH);
	_cursorY++;
	_cursorX = 0;
}

:void fastcall VWriteLine(SI,DL,CX)
{
	$push si
	AL = screenCols;
	AH = 0;
	IF(CX > AX) CX = AX;
	$push cx,ax,dx
	VWRITESTRXYN(SI,0,DL,CX);
	$pop dx,ax,cx
	BH = CL;
	AX -= CX;
	CL = AL;
	AL = DL;
//	VWRITEXYN(' ',BH,AL,AL);
	VWRITEXYN(' ',BH,AL,CL);
	$pop si
}

:void fastcall CLS()
{
	$push es
	AX = _screenCols * _screenRows;
	CX = AX;
	ES = screenBufferSeg;
	DI = 0;
	AX = 720h;
	$repnz $stosw
	$pop es	
}

:char asctmp[20];

:word fastcall INT2ASC(AX,SI,CL)
{
	$push si
	CH = 0;
	BX = SI;
	do
	{
		DX = 0;
		$div cx
		DL += '0';
		IF(DL > '9') DL += 'A'-'9'-1;
		DSBYTE[BX] = DL;
		BX++;
	}while(AX!=0);
	DSBYTE[BX] = AL;
	CX = BX - SI;
	$push cx
	CX >>= 1;
	BX--;
	LOOPNZ(CX)
	{
		DSBYTE[BX]><DSBYTE[SI];
		BX--;
		SI++;
	}
	$pop ax
	$pop si
}


:word fastcall ASC2INT(SI,BL)
{
	AX = 0;
	CX = 0;
	BH = AL;
	
	for(;;)
	{
		CL = DSBYTE[SI];
		SI++;
		IF(CL == 0) BREAK;
		CL -= '0';
		IF(CL > 9) CL -= 'A'-'9'-1;
		IF(CL >= BL)BREAK;
		$mul bx
		AX += CX;
	}
	return AX;
}

:void fastcall VWRITEWORD(AX,CL)
{
	$push ds
	DS = CS;
	INT2ASC(AX,#asctmp,CL);
	VWRITESTR(SI);
	$pop ds
}

:void fastcall VWRITEWORDA(AX,CL,BL)
{
//	$push ds
//	DS = CS;
	$push bx
	INT2ASC(AX,#asctmp,CL);
	$pop bx
	VWRITESTRA(SI,BL);
//	$pop ds
}

:void fastcall SETCURSORBLOCK()
{
	$mov ah,1    	
	$mov cx,000fh
	$int 10h     
}

:void fastcall SETCURSORLINE()
{
	$mov ah,1    
	$mov cx,0d0fh
	$int 10h     
}
