/*============================================================================
  wsBg.c ver.1.00 「ワンダースワン背景制御」
------------------------------------------------------------------------------
												Programmed by Keiichi.Tago.
============================================================================*/
#include "wsBg.h"

/* ==================== スタティック変数 */
int nBgColorMode;								/* カラーモード (0=モノクロ, 1=カラー) */
BYTE far *lpBgObjectAddress[ BGOBJECT_MAX ];	/* オブジェクトのアドレス */
WORD far wSetCharTemp;							/* BG キャラクタ設定用のワーク */
BYTE far BgFontWork[8];							/* フォント格納用ワークエリア */
BYTE far BgFontDrawWork[32];					/* フォント格納用ワークエリア */

/* ==================== 画面スクロール用変数 */
int nScrollScreen;
int nScrollObjectNumber;
int nScrollBgNumber;
int nScrollX;
int nScrollY;
int nScrollXMax;
int nScrollYMax;
int nBgScrollX;
int nBgScrollY;
int nBgSpeed;
int nBgCount;
int nBgAutoVx;
int nBgAutoVy;
int nBgAutoX;
int nBgAutoY;
int nBgAutoSpeed;
int nBgAutoCount;
int nLetterStartNumber;
int nLetterEndNumber;
int nLetterPutNumber;
WORD wScrollColor;
WORD far *lpScrollBgMapData;
/* ==================== エフェクト用 */
int nEffectScreen;	/* エフェクトを使うスクリーン番号 */
int nEffectMode;	/* エフェクトモード番号 */
int nEffectParam1;	/* パラメータ 1 */
int nEffectParam2;	/* パラメータ 2 */
int nEffectParam3;	/* パラメータ 3 */
int nEffectCount;	/* エフェクト処理用カウンタ */
int nEffectLine;	/* 割り込みを起こすライン */
int nEffectFlag;	/* エフェクト用汎用フラグ */
intvector_t Vect;	/* 割り込みベクタ保存用 */
/* ==================== ヌルキャラクタ */
WORD lpNullChr[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* ==================== Sin テーブル */
int bgSinTable[] = {
/*  0*/	   0,  4,  9, 14, 19, 24, 29, 33, 38, 42, 47, 51, 55, 59, 63, 67,
		  70, 74, 77, 80, 83, 85, 88, 90, 92, 94, 95, 97, 98, 98, 99, 99,
/* 32*/	 100, 99, 99, 98, 98, 97, 95, 94, 92, 90, 88, 85, 83, 80, 77, 74,
		  70, 67, 63, 59, 55, 51, 47, 42, 38, 33, 29, 24, 19, 14,  9,  4,
/* 64*/	   0, -4, -9,-14,-19,-24,-29,-33,-38,-42,-47,-51,-55,-59,-63,-67,
		 -70,-74,-77,-80,-83,-85,-88,-90,-92,-94,-95,-97,-98,-98,-99,-99,
/* 96*/	-100,-99,-99,-98,-98,-97,-95,-94,-92,-90,-88,-85,-83,-80,-77,-74,
		 -70,-67,-63,-59,-55,-51,-47,-42,-38,-33,-29,-24,-19,-14, -9, -4,
/*128*/    0,  4,  9, 14, 19, 24, 29, 33, 38, 42, 47, 51, 55, 59, 63, 67,
		  70, 74, 77, 80, 83, 85, 88, 90, 92, 94, 95, 97, 98, 98, 99, 99,
/*160*/	 100, 99, 99, 98, 98, 97, 95, 94, 92, 90, 88, 85, 83, 80, 77, 74,
		  70, 67, 63, 59, 55, 51, 47, 42, 38, 33, 29, 24, 19, 14,  9,  4,
/*192*/	   0, -4, -9,-14,-19,-24,-29,-33,-38,-42,-47,-51,-55,-59,-63,-67,
		 -70,-74,-77,-80,-83,-85,-88,-90,-92,-94,-95,-97,-98,-98,-99,-99,
/*224*/	-100,-99,-99,-98,-98,-97,-95,-94,-92,-90,-88,-85,-83,-80,-77,-74,
		 -70,-67,-63,-59,-55,-51,-47,-42,-38,-33,-29,-24,-19,-14, -9, -4
};
/* ==================== _CS と _DS 定義 */
#ifdef LSI_C
int _asm_inline( char near *asm );
#define _CS _asm_inline( "mov ax, cs" );
#define _DS _asm_inline( "mov ax, ds" );
#endif

/*============================================================
	BG 特殊効果用ライン割り込みコールバック
--------------------------------------------------------------
In  : なし
Out : なし
============================================================*/
void far LcdLineCallback( void )
{
	/* 特定ライン描画時の割り込みルーチン */
	int x;
	int y;
	int n;
	y = ( screen_get_scroll( nEffectScreen ) >> 8 ) & 255;
	switch( nEffectMode ) {
		case SETEFFECT_DIVIDE:
			/* 画面を 2 つに分割する */
			if ( nEffectLine == 0 ) {
				screen_set_scroll( nEffectScreen, nEffectParam2, y );
				lcd_set_interrupt_line( nEffectParam1 );
				nEffectLine = nEffectParam1;
			} else {
				screen_set_scroll( nEffectScreen, nEffectParam3, y );
				lcd_set_interrupt_line( 0 );
				nEffectLine = 0;
			}
			break;
		case SETEFFECT_UNE:
			/* うねうね表示する */
			n = ( ( nEffectLine + nEffectCount ) * ( 8 * nEffectParam1 / 9 ) ) & 255;
			x = bgSinTable[ n ] * nEffectParam2 / 100;
			screen_set_scroll( nEffectScreen, x, y );
			/* 次の割り込みタイミングを設定する */
			nEffectLine = lcd_get_display_line() + 6;
			if ( nEffectLine > 143 ) {
				nEffectLine = 0;
				nEffectCount++;
			}
			lcd_set_interrupt_line( nEffectLine );
			break;
		case SETEFFECT_RASTER1:
			/* ラスタ表示 Type 1 */
			x = ( nBgScrollX + nBgAutoX ) % nEffectParam3;
			if ( ( nEffectLine < nEffectParam1 ) && ( nEffectFlag == 0 ) ) {
				screen_set_scroll( nEffectScreen, x, 0 );
				nEffectLine = nEffectParam1;
				nEffectFlag = 1;
			} else if ( nEffectLine <= nEffectParam2 ) {
				y = nEffectLine - nEffectParam1;
				n = nEffectParam2 - nEffectParam1;
				x += ( x * y / n );
				screen_set_scroll( nEffectScreen, x, 0 );
				nEffectLine = lcd_get_display_line() + 2;
			} else {
				screen_set_scroll( nEffectScreen, x, 0 );
				nEffectLine = 0;
				nEffectFlag = 0;
			}
			/* 次の割り込みタイミングを設定する */
			if ( nEffectLine > 143 ) {
				nBgAutoCount++;
				if ( nBgAutoCount >= nBgAutoSpeed ) {
					nBgAutoX = ( nBgAutoX + nBgAutoVx ) & 255;
					nBgAutoY = ( nBgAutoY + nBgAutoVy ) & 255;
					nBgAutoCount = 0;
				}
				nEffectLine = 0;
				nEffectFlag = 0;
				nEffectCount++;
			}
			lcd_set_interrupt_line( nEffectLine );
			break;
		case SETEFFECT_RASTER2:
			/* ラスタ表示 Type 2 */
			x = ( nBgScrollX + nBgAutoX ) % nEffectParam3;
			if ( ( nEffectLine < nEffectParam1 ) && ( nEffectFlag == 0 ) ) {
				screen_set_scroll( nEffectScreen, x, 0 );
				nEffectLine = nEffectParam1;
				nEffectFlag = 1;
			} else if ( nEffectLine <= nEffectParam2 ) {
				n = nEffectParam2 - nEffectParam1;
				y = n - ( nEffectLine - nEffectParam1 );
				x += ( x * y / n );
				screen_set_scroll( nEffectScreen, x, 0 );
				nEffectLine = lcd_get_display_line() + 7;
			} else {
				screen_set_scroll( nEffectScreen, x, 0 );
				nEffectLine = 0;
				nEffectFlag = 0;
			}
			/* 次の割り込みタイミングを設定する */
			if ( nEffectLine > 143 ) {
				nBgAutoCount++;
				if ( nBgAutoCount >= nBgAutoSpeed ) {
					nBgAutoX = ( nBgAutoX + nBgAutoVx ) & 255;
					nBgAutoY = ( nBgAutoY + nBgAutoVy ) & 255;
					nBgAutoCount = 0;
				}
				nEffectLine = 0;
				nEffectFlag = 0;
				nEffectCount++;
			}
			lcd_set_interrupt_line( nEffectLine );
			break;
	}
}

/*============================================================
	BG の初期化
--------------------------------------------------------------
In  : nSetColorMode (0=白黒モード,
    :                1=ワンダースワンカラーならカラーモードに設定する )
Out : なし
============================================================*/
void wsBgInit( int nSetColorMode )
{
	/* 適切なモードに設定する */
	if ( ( wwc_get_hardarch() == HARDARCH_WS ) || ( nSetColorMode == 0 ) ) {
		/* モノクロモード設定 */
		wwc_set_color_mode( COLOR_MODE_GRAYSCALE );
		/* 0 番のキャラクタは常にヌルキャラクタ */
		font_set_colordata( 0, 1, lpNullChr );
		nBgColorMode = 0;
	} else {
		/* カラーモード設定 */
		wwc_set_color_mode( COLOR_MODE_16COLOR );
		/* 0 番のキャラクタは常にヌルキャラクタ */
		wwc_font_set_colordata( 0, 1, lpNullChr );
		nBgColorMode = 1;
	}
	/* エフェクトは使わない */
	nEffectMode = SETEFFECT_NORMAL;
	nEffectLine = 144;
	/* BG 初期化 */
	nBgScrollX = 0;
	nBgScrollY = 0;
	nBgCount = 0;
	nBgAutoVx = 0;
	nBgAutoVy = 0;
	nBgAutoX = 0;
	nBgAutoY = 0;
	nBgAutoSpeed = 0;
	nBgAutoCount = 0;
	nLetterStartNumber = 256;
	nLetterEndNumber = 383;
	/* SCREEN1 および SCREEN2 をヌルキャラクタで埋めつくす */
	screen_fill_char( SCREEN1, 0, 0, 32, 32, 0 );
	screen_fill_char( SCREEN2, 0, 0, 32, 32, 0x800 );
	/* スクロール位置を初期化する */
	screen_set_scroll( SCREEN1, 0, 0 );
	screen_set_scroll( SCREEN2, 0, 0 );
	/* 背景表示 */
	display_control( display_status() | DCM_SCR1 | DCM_SCR2 );
}

/*============================================================
	BG オブジェクトファイルの設定
--------------------------------------------------------------
In  : nObjectNumber = BG オブジェクト番号
    : lpPath = BG オブジェクトのファイルネーム
Out : なし
============================================================*/
void wsBgSetObjectFile( int nObjectNumber, char far *lpPath )
{
	lpBgObjectAddress[ nObjectNumber ] = mmap( lpPath );
}

/*============================================================
	キャラクタ定義
--------------------------------------------------------------
In  : nObjectNumber = BG オブジェクト番号
    : nChrNumber = 定義するキャラクタ番号
    : nDefineNumber = キャラクタ定義位置
    : nNumOfDefine = 定義するキャラクタ数
Out : なし
============================================================*/
void wsBgSetChr( int nObjectNumber, int nChrNumber, int nDefineNumber, int nNumOfDefine )
{
	WORD far *lpChrHead;
	BYTE far *lpChrData;
/*	WORD far *lpPalData; */
	lpChrHead = (WORD far *)( lpBgObjectAddress[ nObjectNumber ] + 6 );
	lpChrData = (BYTE far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 0 ] );
/*	lpPalData = (WORD far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 1 ] ); */
	/* ヘッダを見てデータ形式を判断する */
	if ( *(BYTE far *)( lpBgObjectAddress[ nObjectNumber ] + 5 ) == 0 ) {
		/* モノクロデータ */
		lpChrData += ( nChrNumber * 16 );
		font_set_colordata( nDefineNumber, nNumOfDefine, lpChrData );
	} else {
		/* カラーデータ */
		lpChrData += ( nChrNumber * 32 );
		wwc_font_set_colordata( nDefineNumber, nNumOfDefine, lpChrData );
	}
}

/*============================================================
	パレット定義
--------------------------------------------------------------
In  : nObjectNumber = BG オブジェクト番号
    : nPaletNumber = 選択パレット番号
    : nDefineNumber = 定義パレット番号 (0〜15)
Out : なし
============================================================*/
void wsBgSetPalet( int nObjectNumber, int nPaletNumber, int nDefineNumber )
{
	WORD far *lpChrHead;
	WORD far *lpPalData;
	int i;
	lpChrHead = (WORD far *)( lpBgObjectAddress[ nObjectNumber ] + 6 );
	lpPalData = (WORD far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 1 ] );
	/* ヘッダを見てデータ形式を判断する */
	if ( *(BYTE far *)( lpBgObjectAddress[ nObjectNumber ] + 5 ) == 0 ) {
		/* モノクロデータ */
		palette_set_color( nDefineNumber, lpPalData[ nPaletNumber ] );
	} else {
		/* カラーデータ */
		for( i=0; i<16; i++ ) {
			wsPalSetColorPalet( nDefineNumber, i, lpPalData[ nPaletNumber * 16 + i ] );
		}
	}
}

/*============================================================
	キャラクタを VRAM へ転送
--------------------------------------------------------------
In  : SCREEN1 または SCREEN2
    : nObjectNumber = BG オブジェクト番号
    : nBgNumber = BG 番号
    : nDefineNumber = 最初のキャラクタ番号
    : nX = 横表示位置
    : nY = 縦表示位置
    : nColor = パレット番号
    : nMode = 配置モード (SETVRAM_NORMAL/SETVRAM_RL_REVERSE/SETVRAM_UD_REVERSE)
Out : なし
============================================================*/
void wsBgSetVram( int nScreen, int nObjectNumber, int nBgNumber, int nDefineNumber, int nX, int nY, int nColor, int nMode )
{
	WORD far *lpChrHead;
/*	BYTE far *lpChrData; */
/*	WORD far *lpPalData; */
	WORD far *lpBgMapData;
	int nXCnt;
	int nYCnt;
	WORD wColor;
	lpChrHead = (WORD far *)( lpBgObjectAddress[ nObjectNumber ] + 6 );
/*	lpChrData = (BYTE far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 0 ] ); */
/*	lpPalData = (WORD far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 1 ] ); */
	lpBgMapData = (WORD far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 2 + 128 + nBgNumber ] );
	wColor = (WORD)( nColor << 9 );
	for ( nYCnt = 0; nYCnt < lpBgMapData[ 1 ]; nYCnt++ ) {
		for ( nXCnt = 0; nXCnt < lpBgMapData[ 0 ]; nXCnt++ ) {
			int nSetY;
			int nSetX;
			nSetX = nXCnt;
			nSetY = nYCnt;
			if ( nMode & SETVRAM_RL_REVERSE ) {
				nSetX = lpBgMapData[ 0 ] - nXCnt - 1;
			}
			if ( nMode & SETVRAM_UD_REVERSE ) {
				nSetY = lpBgMapData[ 1 ] - nYCnt - 1;
			}
			wSetCharTemp = lpBgMapData[ 2 + nSetY * lpBgMapData[ 0 ] + nSetX ] + nDefineNumber + wColor;
			if ( nMode & SETVRAM_RL_REVERSE ) {
				wSetCharTemp |= 0x4000;
			}
			if ( nMode & SETVRAM_UD_REVERSE ) {
				wSetCharTemp |= 0x8000;
			}
			screen_set_char( nScreen, nX + nXCnt, nY + nYCnt, 1, 1, &wSetCharTemp );
		}
	}
}

/*============================================================
	スクロール画面初期化
--------------------------------------------------------------
In  : SCREEN1 または SCREEN2
    : nObjectNumber = BG オブジェクト番号
    : nBgNumber = BG 番号
    : nX = 横表示位置
    : nY = 縦表示位置
    : nColor = パレット番号
Out : なし
--------------------------------------------------------------
・wsBgSetChr でキャラクタを定義する必要があります
・nColor が 0 の場合は MAP データがそのまま転送されます
============================================================*/
void wsBgInitScroll( int nScreen, int nObjectNumber, int nBgNumber, int nX, int nY, int nColor )
{
	WORD far *lpChrHead;
	WORD far *lpBgMapData;
	int nXCnt;
	int nYCnt;
	int i;
	/* オブジェクトのアドレス取得 */
	lpChrHead = (WORD far *)( lpBgObjectAddress[ nObjectNumber ] + 6 );
	lpBgMapData = (WORD far *)( (DWORD)lpBgObjectAddress[ nObjectNumber ] + (DWORD)lpChrHead[ 2 + 128 + nBgNumber ] );
	/* スクロール用パラメータ保存 */
	nScrollScreen = nScreen;
	nScrollObjectNumber = nObjectNumber;
	nScrollBgNumber = nBgNumber;
	nScrollX = 0;
	nScrollY = 0;
	nBgScrollX = 0;
	nBgScrollY = 0;
	nBgCount = 0;
	nBgAutoVx = 0;
	nBgAutoVy = 0;
	nBgAutoX = 0;
	nBgAutoY = 0;
	nBgAutoSpeed = 0;
	nBgAutoCount = 0;
	nScrollXMax = lpBgMapData[ 0 ];
	nScrollYMax = lpBgMapData[ 1 ];
	wScrollColor = (WORD)nColor << 9;
	lpScrollBgMapData = lpBgMapData + 2;
	screen_set_scroll( nScreen, 0, 0 );
	/* 背景非表示 */
	display_control( display_status() & ~( nScreen + 1 ) );
	/* 画面表示 */
	for ( nYCnt = 0; nYCnt < 32; nYCnt++ ) {
		for ( nXCnt = 0; nXCnt < 32; nXCnt++ ) {
			int nMapAdr;
			nMapAdr = ( nYCnt * nScrollXMax + nXCnt ) % ( nScrollXMax * nScrollYMax );
			wSetCharTemp = lpScrollBgMapData[ nMapAdr ] + wScrollColor;
			screen_set_char( nScreen, nXCnt, nYCnt, 1, 1, &wSetCharTemp );
		}
	}
	/* 目的の位置までスクロールする */
	for ( i=0; i<nX / 8; i++ ) {
		wsBgScroll( 8, 0 );
	}
	for ( i=0; i<nX % 8; i++ ) {
		wsBgScroll( 1, 0 );
	}
	for ( i=0; i<nY / 8; i++ ) {
		wsBgScroll( 0, 8 );
	}
	for ( i=0; i<nY % 8; i++ ) {
		wsBgScroll( 0, 1 );
	}
	/* 背景表示 */
	display_control( display_status() | ( nScreen + 1 ) );
}

/*============================================================
	画面をスクロールする
--------------------------------------------------------------
In  : nVx = 横方向の移動量
    : nVy = 縦方向の移動量
Out : なし
============================================================*/
void wsBgScroll( int nVx, int nVy )
{
	int nDrawX;
	int nDrawY;
	int nMapX;
	int nMapY;
	int nMapAdr;
	int i;
	if ( nVx != 0 ) {
		/* 横方向の移動 */
		if ( ( nScrollX & 7 ) == 0 ) {
			nMapX = ( nScrollX / 8 ) % nScrollXMax;
			if ( nMapX < 0 ) {
				nMapX += nScrollXMax;
			}
			nMapY = ( nScrollY / 8 ) % nScrollYMax;
			if ( nMapY < 0 ) {
				nMapY += nScrollYMax;
			}
			if ( nVx > 0 ) {
				/* 右に進む */
				nMapX += 31;
				nMapX %= nScrollXMax;
			} else if ( nVx < 0 ) {
				/* 左に進む */
				nMapX--;
				nMapX %= nScrollXMax;
				if ( nMapX < 0 ) {
					nMapX += nScrollXMax;
				}
			}
			nDrawX = ( nScrollX / 8 - 1 ) & 31;
			nDrawY = ( nScrollY / 8 ) & 31;
			for ( i=0; i<32; i++ ) {
				nMapAdr = nMapY * nScrollXMax + nMapX;
				wSetCharTemp = lpScrollBgMapData[ nMapAdr ] + wScrollColor;
				screen_set_char( nScrollScreen, nDrawX, nDrawY, 1, 1, &wSetCharTemp );
				nDrawY++;
				nDrawY &= 31;
				nMapY++;
				nMapY %= nScrollYMax;
			}
		}
	}
	if ( nVy != 0 ) {
		/* 縦方向の移動 */
		if ( ( nScrollY & 7 ) == 0 ) {
			nMapX = ( nScrollX / 8 ) % nScrollXMax;
			if ( nMapX < 0 ) {
				nMapX += nScrollXMax;
			}
			nMapY = ( nScrollY / 8 ) % nScrollYMax;
			if ( nMapY < 0 ) {
				nMapY += nScrollYMax;
			}
			if ( nVy > 0 ) {
				/* 下に進む */
				nMapY += 31;
				nMapY %= nScrollYMax;
			} else if ( nVy < 0 ) {
				/* 上に進む */
				nMapY--;
				nMapY %= nScrollYMax;
				if ( nMapY < 0 ) {
					nMapY += nScrollYMax;
				}
			}
			nDrawX = ( nScrollX / 8 ) & 31;
			nDrawY = ( nScrollY / 8 - 1 ) & 31;
			for ( i=0; i<32; i++ ) {
				nMapAdr = nMapY * nScrollXMax + nMapX;
				wSetCharTemp = lpScrollBgMapData[ nMapAdr ] + wScrollColor;
				screen_set_char( nScrollScreen, nDrawX, nDrawY, 1, 1, &wSetCharTemp );
				nDrawX++;
				nDrawX &= 31;
				nMapX++;
				nMapX %= nScrollXMax;
			}
		}
	}
	/* MAP スクロール */
	nScrollX += nVx;
	nScrollY += nVy;
	screen_set_scroll( nScrollScreen, nScrollX & 255, nScrollY & 255 );
	/* BG スクロール */
	if ( nBgSpeed != 0 ) {
		int nLoop;
		nLoop = nVx;
		if ( nLoop < 0 ) nLoop = -nLoop;
		for ( i=0; i<nLoop; i++ ) {
			nBgCount++;
			if ( nBgCount >= nBgSpeed ) {
				nBgScrollX = ( nBgScrollX + nVx ) & 255;
				nBgScrollY = ( nBgScrollY + nVy ) & 255;
				screen_set_scroll( 1 - nScrollScreen, nBgScrollX, nBgScrollY );
				nBgCount = 0;
			}
		}
	}
}

/*============================================================
	スクロール横位置の取得
--------------------------------------------------------------
In  : なし
Out : 横位置
============================================================*/
int wsBgGetScrollPositionX( void )
{
	return( nScrollX );
}

/*============================================================
	スクロール縦位置の取得
--------------------------------------------------------------
In  : なし
Out : 縦位置
============================================================*/
int wsBgGetScrollPositionY( void )
{
	return( nScrollY );
}

/*============================================================
	特定位置のキャラクタ番号取得
--------------------------------------------------------------
In  : nX = MAP 横座標
    : nY = MAP 縦座標
Out : キャラクタ番号
============================================================*/
WORD wsBgGetChrNumber( int nX, int nY )
{
	nX = nX % nScrollXMax;
	if ( nX < 0 ) nX += nScrollXMax;
	nY = nY % nScrollYMax;
	if ( nY < 0 ) nY += nScrollYMax;
	return( lpScrollBgMapData[ nY * nScrollXMax + nX ] );
}

/*============================================================
	背景のスクロール速度設定
--------------------------------------------------------------
In  : nSpeed = スクロール速度 (0=しない, 1=1/1, 2=1/2, 3=1/3)
Out : なし
============================================================*/
void wsBgSetBgSpeed( int nSpeed )
{
	nBgSpeed = nSpeed;
}

/*============================================================
	背景の自動スクロール方向設定
--------------------------------------------------------------
In  : nVx = 横方向の移動量
    : nVy = 縦方向の移動量
    ; nSpeed = スクロール速度 (0=しない, 1=1/1, 2=1/2, 3=1/3)
Out : なし
============================================================*/
void wsBgSetBgAutoScroll( int nVx, int nVy, int nSpeed )
{
	nBgAutoVx = nVx;
	nBgAutoVy = nVy;
	nBgAutoSpeed = nSpeed;
}

/*============================================================
	BG 特殊効果設定
--------------------------------------------------------------
In  : nScreen = SCREEN1 または SCREEN2
    : nMode = (SETEFFECT_NORMAL/SETEFFECT_DIVIDE/SETEFFECT_UNE)
	: nParam1
    : nParam2
    : nParam3
Out : なし
--------------------------------------------------------------
・SETEFFECT_NORMAL
    : nParam1 = 0
    : nParam2 = 0
    : nParam3 = 0
・SETEFFECT_DIVIDE
    : nParam1 = 分割する縦表示位置
    : nParam2 = 上半分の横表示位置
    : nParam3 = 下半分の横表示位置
・SETEFFECT_UNE
    : nParam1 = 波の間隔
    : nParam2 = 振幅 (ドット数)
    : nParam3 = 0
・SETEFFECT_RASTER1
	: nParam1 = ラスタ開始縦位置
	: nParam2 = ラスタ終了縦位置
    : nParam3 = 最大スクロール量
・SETEFFECT_RASTER2
	: nParam1 = ラスタ開始縦位置
	: nParam2 = ラスタ終了縦位置
    : nParam3 = 最大スクロール量
============================================================*/
void wsBgSetEffect( int nScreen, int nMode, int nParam1, int nParam2, int nParam3 )
{
	/* 割り込みの初期設定 */
	lcd_set_interrupt_line( 0 );
	nEffectLine = 0;
	nEffectFlag = 0;
#ifdef LSI_C
	Vect.callback = (void (near *)())FP_OFF( LcdLineCallback );
#else
	Vect.callback = (void (near *)())LcdLineCallback;
#endif
	Vect.cs = _CS;
	Vect.ds = _DS;
	if ( nEffectMode != SETEFFECT_NORMAL ) {
		nEffectLine = 144;
		lcd_set_interrupt_line( 144 );
		sys_interrupt_reset_hook( SYS_INT_DISPLINE, &Vect );
	}
	if ( nMode != SETEFFECT_NORMAL ) {
		sys_interrupt_set_hook( SYS_INT_DISPLINE, &Vect, &Vect );
	}
	/* エフェクトパラメータ設定 */
	nEffectScreen = nScreen;
	nEffectMode = nMode;
	nEffectParam1 = nParam1;
	nEffectParam2 = nParam2;
	nEffectParam3 = nParam3;
}

/*============================================================
	BG 特殊効果のパラメータ設定
--------------------------------------------------------------
In  : nParam1
    : nParam2
    : nParam3
Out : なし
============================================================*/
void wsBgSetEffectParam( int nParam1, int nParam2, int nParam3 )
{
	nEffectParam1 = nParam1;
	nEffectParam2 = nParam2;
	nEffectParam3 = nParam3;
}

/*============================================================
	1 キャラクタ表示
--------------------------------------------------------------
In  : nScreen = SCREEN1 または SCREEN2
    : nDefineNumber = 最初のキャラクタ番号 (-1 の場合は自動)
    : nX = 横表示位置
    : nY = 縦表示位置
    : nPalet = パレット
Out : なし
============================================================*/
void wsBgPutChar( int nScreen, int nDefineNumber, int nX, int nY, int nPalet )
{
	wSetCharTemp = nDefineNumber + ( nPalet << 9 );
	screen_set_char( nScreen, nX, nY, 1, 1, &wSetCharTemp );
}

/*============================================================
	文字表示用キャラクタ番号設定
--------------------------------------------------------------
In  : nDefineNumber = 先頭定義番号
Out : なし
============================================================*/
void wsBgSetPutRange( int nStartNumber, int nEndNumber )
{
	nLetterStartNumber = nStartNumber;
	nLetterEndNumber = nEndNumber;
	nLetterPutNumber = nStartNumber;
}

/*============================================================
	1 文字定義
--------------------------------------------------------------
In  : nDefineNumber = 最初のキャラクタ番号 (-1 の場合は自動)
    : nCode = 文字コード
Out : なし
============================================================*/
void wsBgSetLetter( int nDefineNumber, int nCode, int nColor, int nShadowColor )
{
	int i, j, k;
	text_get_fontdata( nCode, BgFontWork );
	if ( nBgColorMode == 0 ) {
		/* モノクロモード */
		font_set_monodata( nDefineNumber, 1, BgFontWork );
	} else {
		int nFlag;
		/* カラーモード */
		if ( nShadowColor != 0 ) {
			memset( BgFontDrawWork, 0, sizeof( BgFontDrawWork ) );
		}
		for( i=7; i>=0; i-- ) {
			if ( nShadowColor != 0 ) {
				for( j=0; j<4; j++ ) {
					nFlag = ( nShadowColor >> j ) & 1;
					if ( nFlag == 1 ) {
						for( k=-1; k<2; k++ ) {
							if ( ( ( i + k ) >= 0 ) && ( ( i + k ) < 8 ) ) {
								BgFontDrawWork[ ( i + k ) * 4 + j ] |= BgFontWork[ i ] >> 1;
								BgFontDrawWork[ ( i + k ) * 4 + j ] |= BgFontWork[ i ];
								BgFontDrawWork[ ( i + k ) * 4 + j ] |= BgFontWork[ i ] << 1;
							}
						}
					} else {
						BgFontDrawWork[ i * 4 + j ] = 0;
					}
				}
			}
			for( j=0; j<4; j++ ) {
				BYTE by1Line;
				nFlag = ( nColor >> j ) & 1;
				if ( nFlag == 1 ) {
					by1Line = BgFontWork[ i ];
				} else {
					by1Line = 0;
				}
				if ( nShadowColor != 0 ) {
					BgFontDrawWork[ i * 4 + j ] &= ~BgFontWork[ i ];
					BgFontDrawWork[ i * 4 + j ] |= by1Line;
				} else {
					BgFontDrawWork[ i * 4 + j ] = by1Line;
				}
			}
		}
		wwc_font_set_colordata( nDefineNumber, 1, BgFontDrawWork );
	}
}

/*============================================================
	1 文字表示
--------------------------------------------------------------
In  : nScreen = SCREEN1 または SCREEN2
    : nDefineNumber = 最初のキャラクタ番号 (-1 の場合は自動)
    : nX = 横表示位置
    : nY = 縦表示位置
    : nPalet = パレット番号
    : nColor = 色 (0〜15) ※カラーモードのみ
    : nShadowColor = 影の色 (0〜15) ※カラーモードのみ
    : nCode = 文字コード
Out : なし
============================================================*/
void wsBgPutLetter( int nScreen, int nDefineNumber, int nX, int nY, int nPalet, int nColor, int nShadowColor, int nCode )
{
	if ( nDefineNumber == -1 ) {
		nDefineNumber = nLetterPutNumber;
		nLetterPutNumber++;
		if ( nLetterPutNumber > nLetterEndNumber ) {
			nLetterPutNumber = nLetterStartNumber;
		}
	}
	wsBgSetLetter( nDefineNumber, nCode, nColor, nShadowColor );
	wSetCharTemp = nDefineNumber + ( nPalet << 9 );
	screen_set_char( nScreen, nX, nY, 1, 1, &wSetCharTemp );
}

/*============================================================
	文字列表示 (全角のみ)
--------------------------------------------------------------
In  : nScreen = SCREEN1 または SCREEN2
    : nDefineNumber = 最初のキャラクタ番号 (-1 の場合は自動)
    : nX = 横表示位置
    : nY = 縦表示位置
    : nPalet = パレット番号
    : nColor = 色 (0〜15) ※カラーモードのみ
    : nShadowColor = 影の色 (0〜15) ※カラーモードのみ
    : lpString = 文字列
Out : なし
============================================================*/
void wsBgPutString( int nScreen, int nDefineNumber, int nX, int nY, int nPalet, int nColor, int nShadowColor, char *lpString )
{
	int nCode;
	while( *lpString != '\0' ) {
#ifdef LSI_C
		nCode = lpString[0] * 256 + lpString[1];
#else
		nCode = lpString[1] * 256 + lpString[0];
#endif
		wsBgPutLetter( nScreen, nDefineNumber, nX, nY, nPalet, nColor, nShadowColor, nCode );
		nX++;
		if ( nDefineNumber != -1 ) {
			nDefineNumber++;
		}
		lpString += 2;
	}
}
