/***  スプライト制御ルーチン   ***/

#include <dos   .h>
#include <stdio .h>
#include <stdlib.h>
#include <string.h>
#include <snd.h>
#include <spr.h>
#include <egb.h>

#include "graphic .h"
#include "sound   .h"
#include "calc    .h"
#include "spr_defs.h"
#include "spr_drv .h"

#include "str_sub .h"

#define	GRADPAL_MAX		( 16*16 << 4 )
#define GRADPAL_P		( char *)( gradpal_org + gradpal_siz*16*gradpal_n )
#define PBB(n)		palette_buf.col[n].B
#define PBR(n)		palette_buf.col[n].R
#define PBG(n)		palette_buf.col[n].G
#define PB(n)		pal_set.col[n].B
#define PR(n)		pal_set.col[n].R
#define PG(n)		pal_set.col[n].G

int		bright_zero = 0, bright_lmt = 256 ;
int		bright_lv = 0, bright_slv = 0, brlv_lmt = 0 ;
int		gradpal_ofs = -1, gradpal_n = 0, gradpal_step = 1 ;
int		gradpal_div = 8, gradpal_siz = 8 ;
int		pattern_idx[ IDX_MAX ];
CARD	palstk_buf[ PALSTK_MAX ];
CARD	gradpal_org[ GRADPAL_MAX ], gradpal_stk[ GRADPAL_MAX ];
int		spr_swi[2] = { SPR_OFF, 0 };

CARD	*imgmap_p ;
int		spr_vx , spr_vy ;
int		imgmap_wx = 256, imgmap_wy = 256 ;
int		imgmap_wdx = 256<<4, imgmap_wdy = 256<<4 ;
int		scr_chx, scr_chy, scr_dtx, scr_dty ;
int		map_chx, map_chy, map_dtx, map_dty, map_frx, map_fry ;

/*  スプライト初期化  */

void sprite_init( void )
{
	int i ;

	for( i = 0 ; i < 1024 ; i++ ) SPR_setAttribute( i,1,1,128,SPR_OFF );
	SPR_START();
}

void sprite_end( void )
{
	SPR_STOP();
}

/***  ウエイト  ***/

void wait_sprtime( int c )
{
	for( ; 0 < c ; --c ) SPR_READY();
}

/*	スプライトマップスクロールルーチン	*/

void scroll( int xm, int ym )
{
	register CARD *p ;
	CARD	ch ;
	int		ofs, sign, x, y, sn, i ;

	if( 16 < _abs(xm) || 16 < _abs(ym) ){
		/*  安全装置  */
		wait_Rtrg(), wait_rel();
		box_fill( 0, 200, 18*8, 8, PSET, 0, 0 );
		if( xm != 0 ){
			x = SGN( xm, 16 );
			while( 16 < _abs(xm) ) scroll( x, 0 ), xm -= x ;
			scroll( xm, 0 );
		}
		if( ym != 0 ){
			y = SGN( ym, 16 );
			while( 16 < _abs(ym) ) scroll( 0, y ), ym -= y ;
			scroll( 0, ym );
		}
		return ;
	}

	spr_vx	= ( spr_vx - xm )& 511, spr_vy = ( spr_vy - ym )& 511 ;
	scr_dtx = ( scr_dtx + xm + SCR_WD )% SCR_WD, x = scr_dtx>>4 ;
	scr_dty = ( scr_dty + ym + SCR_WD )% SCR_WD, y = scr_dty>>4 ;
	map_dtx = ( map_dtx + xm + IMGMAP_WDX )% IMGMAP_WDX, map_chx = map_dtx>>4 ;
	map_dty = ( map_dty + ym + IMGMAP_WDY )% IMGMAP_WDY, map_chy = map_dty>>4 ;
	map_frx	= ( map_dtx - SCR_OFSX + imgmap_wdx )% imgmap_wdx ;
	map_fry = ( map_dty - SCR_OFSY + imgmap_wdy )% imgmap_wdy ;

	SPR_setOffset( spr_vx, spr_vy );

	if( scr_chy != y ){
		ofs = ( (scr_chy + ( ym < 0 ? SCR_WC-1:0 ) )% SCR_WC)*SCR_WC+BACK_IDX ;
		p	= &IMGMAP_BUF( 0, (map_chy+( 0 < ym ? SCR_WC-1 :0 )) % imgmap_wy );
		scr_chy = y ;
		sign = ( 0 < ym ? SCR_WD : -SCR_WD );

		for( i = 0 ; i < SCR_WC ; i++ ){
			ch = p[ ( map_chx + i )% imgmap_wx ];
			sn = ofs +( x + i )% SCR_WC ;
			SPR_MOVE1( sn, 0, sign ), SPR_SET0( sn, ch | OFS_ON ) ;
		}
	}

	if( scr_chx != x ){
		ofs = ( scr_chx +( xm < 0 ? SCR_WC-1 : 0 ) )% SCR_WC + BACK_IDX ;
		p	= &IMGMAP_BUF( (map_chx+( 0 < xm ? SCR_WC-1 :0 )) % imgmap_wx, 0 );
		scr_chx = x ;
		sign = ( 0 < xm ? SCR_WD : -SCR_WD );
		
		for( i = 0 ; i < SCR_WC ; i++ ){
			ch = p[ (( map_chy + i )% imgmap_wy )*imgmap_wx ];
			sn = ofs +( ( scr_chy + i )% SCR_WC )*SCR_WC ;
			SPR_MOVE1( sn, sign, 0 ), SPR_SET0( sn, ch | OFS_ON );
		}
	}
}

void map_init( void )
{
	int x, y, sn ;

	scr_dtx = scr_dty = scr_chx = scr_chy = spr_vx = spr_vy = 0 ;
	map_dtx = map_dty = 0 ;

	SPR_setOffset( spr_vx , spr_vy );

	for( y = 0 ; y < SCR_WC ; y++ ){
		for( x = 0 ; x < SCR_WC ; x++ ){
			sn = x + y * SCR_WC + BACK_IDX ;
			SPR_SET0( sn, 0 | OFS_ON );
			SPR_POS1( sn, ( x*16 + SCR_OFSX )& 511, ( y*16 + SCR_OFSY )& 511 );
		}
	}
}

void map_reset( int x, int y )
{
	int xm, ym ;
	int ch, sn ;

	xm = map_dtx & 15, ym = map_dty & 15 ;
	if( 0 < xm || 0 < ym ) scroll( -xm, -ym );
	imgmap_wdx = imgmap_wx << 4, imgmap_wdy = imgmap_wy << 4 ;
	map_chx = ( imgmap_wx + x )% imgmap_wx, map_dtx = map_chx << 4 ;
	map_chy = ( imgmap_wy + y )% imgmap_wy, map_dty = map_chy << 4 ;
	map_frx	= ( map_dtx - SCR_OFSX + imgmap_wdx )% imgmap_wdx ;
	map_fry = ( map_dty - SCR_OFSY + imgmap_wdy )% imgmap_wdy ;

	for( y = 0 ; y < SCR_WC ; y++ ){
		sn = ( ( scr_chy + y )% SCR_WC )*SCR_WC + BACK_IDX ;
		for( x = 0 ; x < SCR_WC ;x++ ){
			ch = IMGMAP_BUF( (map_chx+x)% imgmap_wx, (map_chy+y)% imgmap_wy );
			SPR_SET0( sn +(scr_chx+x)% SCR_WC, ch | OFS_ON );
		}
	}
}

/***  パレット輝度操作  ***/

#define SET_SPAL(h,v,p)	\
	cl = ( *pb>>10 & 31 )+(p), *pc  = (h) ? cl<<10 : (v)<<10,\
	cl = ( *pb>> 5 & 31 )+(p), *pc |= (h) ? cl<< 5 : (v)<< 5,\
	cl = ( *pb	   & 31 )+(p), *pc |= (h) ? cl	   : (v)	, ++pc, ++pb

void gradpal_bright_level( int lv, int all )// グラデーションパレットストック用
{
	register CARD	*pb, *pc ;
			 int	i, cl, slv ;

	pb = gradpal_org, pc = gradpal_stk ;

	slv = ( all <= BLV_ALL && brlv_lmt < lv )? brlv_lmt : lv ;
	if(slv<0) for( i=GRADPAL_MAX ; 0<i ; --i ) SET_SPAL(  0<cl, 0,slv );
	else	  for( i=GRADPAL_MAX ; 0<i ; --i ) SET_SPAL( cl<31,31,slv );
}

void _bright_level( int lv, int all, unsigned long mask )
{
	register CARD		*pb, *pc ;
			 CARD		buf[ PALSTK_MAX ];
			 PALET_S	pal_set ;
			 int		i, c, cl, vol, mbt, slv ;

	slv = ( all <= BLV_ALL && brlv_lmt < lv )? brlv_lmt			   : lv ;
	vol = ( all != BLV_PART					)? (256-bright_lmt)*16 :  0 ;
	pc	= buf, pb = palstk_buf, mbt = mask ;

	if(slv<0) for( i=bright_lmt*16 ; 0<i ; --i ) SET_SPAL( 0<cl, 0,slv);
	else	  for( i=bright_lmt*16 ; 0<i ; --i ) SET_SPAL(cl<31,31,slv);

	if( lv < 0 ){	/*  −  */
		for( i = vol ; 0 < i ; --i ) SET_SPAL(  0 < cl,  0, lv );
		for( i = c = 0 ; i <= 15 ; ++i, mbt >>= 1 ){
			if( ( mbt & 1 ) == 0 ) continue ;
			cl = PBB(i)+lv*8, PB(c) = 0 < cl ? cl : 0 ;
			cl = PBR(i)+lv*8, PR(c) = 0 < cl ? cl : 0 ;
			cl = PBG(i)+lv*8, PG(c) = 0 < cl ? cl : 0 ;
			pal_set.col[c++].num1 = i ;
		}
	}else{			/*  ＋  */
		for( i = vol ; 0 < i ; --i ) SET_SPAL( cl < 31, 31, lv );
		for( i = c = 0 ; i <= 15 ; ++i, mbt >>= 1 ){
			if( ( mbt & 1 ) == 0 ) continue ;
			cl =PBB(i)+lv*8, PB(c) = cl<255 ? cl:255 ;
			cl =PBR(i)+lv*8, PR(c) = cl<255 ? cl:255 ;
			cl =PBG(i)+lv*8, PG(c) = cl<255 ? cl:255 ;
			pal_set.col[c++].num1 = i ;
		}
	}
	SPR_READY();
	if( mask != 0 ) pal_set.palette = c, EGB_palette(ework,0,(char *)&pal_set);
	SPR_setPaletteBlock( 256, bright_lmt + vol/16, ( char *)buf );
}

void bright_level( int level,int step,int wait_c,int all,unsigned long mask )
{
	int		c, lv, blv ;

	blv = ( all == BLV_PART )? bright_slv : bright_lv ;
	if( blv == level || ( bright_zero && all == BLV_PART )) return ;
	if( 0 <= gradpal_ofs ){
		memcpy( palstk_buf + gradpal_ofs*16, GRADPAL_P, gradpal_siz*16*2 );
	}
	lv = blv +( step = SGN( level - blv, _abs(step) ) );
	for( c = _abs( level - lv ) ; 0 <= c ; c -= _abs(step), lv += step  ){
		_bright_level( lv, all, mask ), wait_sprtime( wait_c );
	}
	if( level != lv - step	) _bright_level( level, all, mask );
	if( 0 <= gradpal_ofs	) gradpal_bright_level( level, all );

	bright_slv = ( all <= BLV_ALL && brlv_lmt < level )? brlv_lmt : level ;
	if( BLV_ALL <= all ) bright_zero = (( bright_lv = level ) == -32 && all );
}

/***  白色画面のままフェイドアウト  ***/

void bright_down( int step, int wait_c, unsigned long mask )
{
	register	CARD		*pc ;
			 	CARD		buf[ PALSTK_MAX ];
				PALET_S		pal_set ;
	int			i, c, mbt, lv ;

	if( bright_lv < 32 ) return ;
	step	= _abs( step );

	for( lv = bright_lv - step ; 0 <= lv ; lv -= step ){
		pc	= buf ;
		for( i = 256*16 ; 0 < i ; --i ) *pc++ = ( lv<<10 )+( lv<<5 )+( lv );
		for( i = c = 0, mbt = mask ; i < 16 ; ++i, mbt >>= 1 ){
			if( ( mbt & 1 )!= 0 ){
				PB(c) = lv*8+31, PR(c) = lv*8+31, PG(c) = lv*8+31 ;
				pal_set.col[c].num1 = i, ++c ;
			}
		}
		SPR_READY();
		SPR_setPaletteBlock( 256, 256, ( char *)buf );
		if( mask != 0 )
			pal_set.palette = c, EGB_palette( ework, 0, ( char * ) &pal_set );
		wait_sprtime( wait_c );

		if( 0 < lv && lv - step < 0 ) lv = step ;
	}
	bright_lv = -32, bright_zero = ON ;
}

/***  データ読み込み  ***/

int load_data( char *nam, void *adr, int offset, int size )
{
	FILE *fp;

	if( (fp=fopen(nam,"rb")) == NULL) return 1 ;
	fseek ( fp, offset, SEEK_SET );
	fread ( (char *)adr, size , 1 , fp );
	fclose( fp );
	return 0 ;
}

int load_imagemap( char *fname, int buf_swi )
{
	FILE	*fp ;
	char	head[16];

	if( ( fp = fopen(fname,"rb") ) == NULL ) return 1 ;

	fread ( (char *)head, 16, 1 , fp );
	if( memcmp( head, "MAP_DATA", 8 ) != 0 ) return 1 ;
	imgmap_wx = WORD( head + 12 ), imgmap_wy = WORD( head + 14 );
	imgmap_wdx = imgmap_wx << 4, imgmap_wdy = imgmap_wy << 4 ;

	if( buf_swi ){
		if( imgmap_p != NULL ) free( imgmap_p );
		imgmap_p = malloc( imgmap_wx * imgmap_wy * 2 );
		if( imgmap_p == NULL ) return 1 ;
	}
	fread( (char *)imgmap_p, imgmap_wx << 1, imgmap_wy, fp );

	fclose(fp);

	return 0 ;

}

int load_sprite( char *fname, int spr_ofs, int pal_ofs )
{
	FILE	*fp ;
	CARD	pat_idx ;
	char	head[16], spr_buf[ SPR_BK32K ], *p ;
	int 	pal_sz, pat_sz, sn, bksz, PTR_f ;

	if( ( fp = fopen( fname, "rb" ) ) == NULL ) return 1 ;
	fread( head, 16, 1, fp );

	PTR_f = ( _memicmp( strchr( fname, '.' ), ".PTR", 4 ) == 0 );
	if( PTR_f == 0 ){
		pat_sz = DWORD( head +  8 );
		pal_sz = DWORD( head + 12 );
	}else{
		pat_sz = WORD( head + 14 )*( SPR_BH + SPR_BK32K );
		pal_sz = 0 ;
	}

	/* パレット読み込み */
	if( 0 < pal_sz ){
		if( pal_ofs < 256 ){
			p = (char *)( palstk_buf + pal_ofs*16 );
			fread( p, pal_sz, 1, fp );
			SPR_setPaletteBlock( pal_ofs + 256, pal_sz / PAL_BLOCK, p );
		}else if( 0 <= gradpal_ofs ){
			pal_ofs -= 256 ;
			fread( (char *)( gradpal_org + pal_ofs*16 ), pal_sz, 1, fp );
			memcpy( palstk_buf + gradpal_ofs*16, GRADPAL_P, gradpal_siz*16*2 );
			SPR_setPaletteBlock( gradpal_ofs + 256, gradpal_siz, GRADPAL_P );
		}
	}

	/* SPRITE READ */
	for( sn = spr_ofs ; 0 < pat_sz ; pat_sz -= bksz*128 + SPR_BH, sn += bksz ){

		fread( &pat_idx, SPR_BH, 1, fp );
		if( ( pat_idx & 0x8000 ) == 0 || PTR_f ){
			bksz = 4, pattern_idx[ sn ] = 0x8100 ;
		}else{
			bksz = 1, pattern_idx[ sn ] = pat_idx + pal_ofs ;
		}
		fread( spr_buf, bksz * 128, 1, fp );
		SPR_define( ( bksz == 4 ), sn + 128, 1, 1, spr_buf );
	}

	fclose(fp);
	return 0 ;
}
