//
/***  シューティンゲーム用スプライトキャラクター制御  ***/

#include <stdefs.h>
#include <spr.h>
#include <snd.h>
#include "calc    .h"
#include "spr_defs.h"
#include "spr_drv .h"

#include <fmcfrb.h>
#include "graphic.h"
#include "sound  .h"
#include "str_sub.h"

#define NO		-1
#define RIGHT	6*4096
#define DOWN	3*4096
#define LEFT	5*4096

#define SPR_SETa(sn,pt,pl,x,y)	SPR_setAttribute(sn,x,y,(pt)+128,(pl)|0x8100)
#define SPR_SETb(sn,pt,pl)		SPR_setAttribute(sn,1,1,(pt)+128,(pl)|0x8100)
#define SPR_SETc(sn,pt,pl)		SPR_setAttribute(sn,2,2,(pt)+128,(pl)|0x8100)
#define SPR_POSa(sn,x,y,xs,ys,sz)	SPR_setPosition(sz,sn,xs,ys,x,y)
#define SPR_POSb(sn,x,y)			SPR_setPosition( 0,sn, 1, 1,x,y)
#define SPR_POSc(sn,x,y)			SPR_setPosition( 0,sn, 2, 2,x,y)

#define FRM_IN(x,y)	\
	( ((x)+128)% imgmap_wdx < 256+128*2 && ((y)+128)% imgmap_wdy < 256+128*2 )
#define SCRX(n)		( ( (n)- map_frx )& 511 )
#define SCRY(n)		( ( (n)- map_fry )& 511 )

#define ADJ_X	pat_pos[ cp->ajst + pos ].x
#define ADJ_Y	pat_pos[ cp->ajst + pos ].y
#define ADJ_XS	opt_pos[ cp->opt.ajst + pos ].x
#define ADJ_YS	opt_pos[ cp->opt.ajst + pos ].y
#define ADJ_BX	pat_pos[ blp->ajst + blp->dir ].x
#define ADJ_BY	pat_pos[ blp->ajst + blp->dir ].y

#define IDX_ENT		( SPR_MAX + 1 - MAIN_IDX ) /* 1008 */
#define IDX_LMT		( SPR_MAX + 1 - BAK1_IDX ) /*  752 */

	   CARD		spr_dir[4]={ 0, RIGHT, DOWN, LEFT };
static CARD		spr_turn[4][4] = {
	0	   , 1		, 2		 , 3	  ,	2+RIGHT, 0+RIGHT, 3+RIGHT, 1+RIGHT,
	3+DOWN , 2+DOWN , 1+DOWN , 0+DOWN , 1+LEFT , 3+LEFT , 0+LEFT , 2+LEFT 
};

DSPCH_S		chr[ 20 ];
DCPOS_S		chr_pos[ 20 * 8 ];
BULLET_S	bullet[ BULLET_MAX ];
EFFECT_S	effect_ch[ 20 ];

	   int		show_max = 0, bullet_vol = 0, efxch_c = 0, efxch_spc = 0 ;
static int		chrs_idxmax ;

/*	IDX_LMT	   〜 IDX_ENT-1  使用可能全キャラクターエリア
	chrs_idxmax				 前回まで使ったスプライト				*/

/***  連結キャラ表示  ***/

int set_chrmulti( int n, int idx, int px, int py )
{
	register DCPOS_S	*dp ;
			 int		pal ;

	dp = & chr_pos[ n << 3 ], pal = chr[n].pal ;
	SPR_SETb( idx+0, dp->pat, pal | dp->swi );
	SPR_POSb( idx+0, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+1, dp->pat, pal | dp->swi );
	SPR_POSb( idx+1, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+2, dp->pat, pal | dp->swi );
	SPR_POSb( idx+2, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+3, dp->pat, pal | dp->swi );
	SPR_POSb( idx+3, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+4, dp->pat, pal | dp->swi );
	SPR_POSb( idx+4, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+5, dp->pat, pal | dp->swi );
	SPR_POSb( idx+5, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+6, dp->pat, pal | dp->swi );
	SPR_POSb( idx+6, px + dp->x - 8, py + dp->y - 8 ), dp++ ;
	SPR_SETb( idx+7, dp->pat, pal | dp->swi );
	SPR_POSb( idx+7, px + dp->x - 8, py + dp->y - 8 );

	return( idx + 8 );
}

/***  キャラクター表示  ***/

int chrs_put( int max, int xm, int ym ) /*  ( xm, ym )はスクロールの幅  */
{
	static	 LCARD		gradpal_c = 0 ;
	register DSPCH_S	*cp ;
	register BULLET_S	*blp ;
	register EFFECT_S	*fxp ;
	int		frm_in, p_ang, ang, pos, pat, opat, adr, oadr ;
	int		n, px, py, idx, x, y, hs, vs, sz ;
	char	*ent ;

	SPR_READY();
	if( xm != 0 || ym != 0 ) scroll( xm, ym );

	/*  パレット操作  */
	if( 0 <= gradpal_ofs ){
		if( gradpal_step <= ++gradpal_c ){
			SPR_setPaletteBlock(
				gradpal_ofs + 256, gradpal_siz,
				( char *)( gradpal_stk + gradpal_siz * 16 * gradpal_n ) );
			gradpal_c = 0, ++gradpal_n, gradpal_n %= gradpal_div ;
		}
	}

	idx = IDX_LMT ;

	/*  キャラクター表示  */
	for( cp = &chr[ n = max ] ; 0 <= n ; --n,  --cp ){
		px = ( CHX < map_frx ? imgmap_wdx : 0 )+ CHX - map_frx ;
		py = ( CHY < map_fry ? imgmap_wdy : 0 )+ CHY - map_fry ;
		sz = ( hs = cp->size >> 8 & 255 )*( vs = cp->size & 255 );

		if( cp->swi == 0 || FRM_IN( px, py ) == 0 ) continue ;

		ang		= cp->ang +( 1 << cp->ang_sft - 1 );
		p_ang	= ( ang >> 6 )& 3 ;
		pos		= ( ( ang & 255 )>> cp->ang_sft );
		adr		= cp->c	   + cp->pat_ofs  *( ( ang & 63 )>> cp->ang_sft );
		oadr	= CH_OPT.c + CH_OPT.slant *( ( ang & 63 )>> cp->ang_sft );

		/*  パターンの書き込み  */
		if( ( cp->set_flag & VPT ) == 0 ){
			pat = cp->pat + adr, opat = cp->pat + oadr ;
		}else{
			pat = cp->pat	   , opat = CH_OPT.pat ;
			ent = patstk_ent[ cp->psn ].buf ;
			if( cp->psc != adr ){
				SPR_define( 0, pat+128, sz, 1, ent +(  adr << 7 ) );
				cp->psc = adr ;
			}
			if( CH_OPT.swi && CH_OPT.psc != oadr ){
				SPR_define( 0,opat+128,  1, 1, ent +( oadr << 7 ) );
				CH_OPT.psc = oadr ;
			}
		}

		if( CPFLAG(MUL+TAL) == MUL ) idx = set_chrmulti( n, idx, px, py );

		switch( cp->size ){ /*  メインキャラ  */
		case 0x0202 :/*  32×32  */
			SPR_SETb( idx+0, pat + spr_turn[p_ang][0], cp->pal );
			SPR_SETb( idx+1, pat + spr_turn[p_ang][1], cp->pal );
			SPR_SETb( idx+2, pat + spr_turn[p_ang][2], cp->pal );
			SPR_SETb( idx+3, pat + spr_turn[p_ang][3], cp->pal );
			break ;
		case 0x0101 :/*  16×16  */
			SPR_SETb( idx, pat + spr_dir[p_ang], cp->pal );
			break ;
		case 0 : break ;
		default:/*  無制限  */
			switch( p_ang ){
			case 0 : SPR_SETa( idx, pat, cp->pal, hs, vs ); break ;
			case 2 :
				for( x = 0 ; x < vs * hs ; x++ ){
					SPR_SETb( idx +x, pat + sz - x - 1 + DOWN, cp->pal );
				} break ;
			case 1 :
				x = hs, hs = vs, vs = x ;
				for( y = 0 ; y < vs ; y++ ){
				  for( x = 0 ; x < hs ; x++ ){
					SPR_SETb( idx+x+y*hs,pat+sz-(x+1)*vs+y+RIGHT,cp->pal );
				  }
				} break ;
			case 3 :
				x = hs, hs = vs, vs = x ;
				for( y = 0 ; y < vs ; y++ ){
				  for( x = 0 ; x < hs ; x++ ){
					SPR_SETb( idx+x+y*hs,pat-1 +(x+1)*vs-y+ LEFT,cp->pal );
				  }
				} break ;
			}
		}
		SPR_POSa( idx, px + ADJ_X, py + ADJ_Y, hs, vs, 0 );
		idx += sz ;

		if( CPFLAG(MUL+TAL) == MUL+TAL ) idx = set_chrmulti( n, idx, px, py );
	}

	/*  エフェクトキャラ表示  */
	for( n = efxch_c - 1 ; 0 <= n ; --n ){
		fxp = & effect_ch[ n ];
		px = ( fxp->x.HL.H < map_frx ? imgmap_wdx: 0 )+ fxp->x.HL.H - map_frx ;
		py = ( fxp->y.HL.H < map_fry ? imgmap_wdy: 0 )+ fxp->y.HL.H - map_fry ;
		if( FRM_IN( px, py ) == OFF || ( fxp->swi & 1 ) == 0 ) continue ;

		sz = ( hs = fxp->size >> 8 & 255 )*( vs = fxp->size & 255 );
		SPR_SETa( idx, fxp->pat + fxp->c, fxp->pal, hs, vs );
		SPR_POSa( idx, px - hs*8, py - vs*8, hs, vs, 0 );
		idx += sz ;
	}

	/*  弾丸表示  */
	for( n = bullet_vol - 1 ; 0 <= n ; --n ){
		blp = &bullet[n] ;
		frm_in = ( blp->XH+16 & 511 ) <= 287 && ( blp->YH+16 & 511 ) <= 287 ;
		if( ( blp->swi = blp->swi && frm_in ) == ON ){
			SPR_SETb( idx, blp->pat+blp->c+spr_dir[blp->dir], blp->pal );
			SPR_POSb( idx, blp->XH + ADJ_BX, blp->YH + ADJ_BY );
			++idx ;
		}
	}

	n = chrs_idxmax - idx ;

	while( 0 < n ){
		sz = ( 256 <= n )? 256 : n, n -= sz, chrs_idxmax -= sz ;
		if( SPR_SETa( chrs_idxmax, 0, SPR_OFF, sz, 1 ) ){
			BEEP_DMY();
			put_string( 0, 232, set_num( sz, -3 ), cvcl[7] );
		}
	}
	return( chrs_idxmax = idx );
}

/***  キャラクター登録  （sizeとset_flagのみ設定）***/

int chrs_entry( int swi )
{
	register DSPCH_S	*cp ;
			 int		i, sz ;

	efxch_c = efxch_spc = 0 ;
	for( i = 0 ; i < bullet_vol ; i++ ) bullet[i].swi = OFF ;
	for( i = 0 ; i <= 19 ; i++ ) effect_ch[i].swi = OFF, effect_ch[i].cn = NO ;
	for( cp = &chr[ i = 0 ] ; i <= show_max ; i++, cp++ ){
		cp->efx_n = cp->psc = CH_OPT.psc = NO, cp->set_flag &= ~POV ;
	}
	chrs_idxmax = IDX_ENT ;

	if( swi ){
		chrs_put( show_max, 0, 0 );
	}else{
		i = IDX_ENT - IDX_LMT ;
		while( 0 < i ){
			sz = ( 256 <= i )? 256 : i, i -= sz, chrs_idxmax -= sz ;
			if( SPR_SETa( chrs_idxmax, 0, SPR_OFF, sz, 1 ) ){
				BEEP_DMY();
				put_string( 0, 232, set_num( sz, -3 ), cvcl[7] );
			}
//			SPR_SETa( chrs_idxmax, 0, SPR_OFF, sz, 1 ); // 256を越えるとエラー
		}
	}
	return 0 ;
}

/***  スクロールサブ  ***/

int scroll_x( int move_x )
{
	int xm, pad, trig ;

	trig = 0 ;
	if( move_x == 0 ) return 0 ;
	for( xm = SGN( move_x, 16 ) ; 16 < ABS( move_x ) ; move_x -= xm ){
		SND_joy_in_2( 0, &pad ), trig |= ( ~pad & 0xf0 );
		chrs_put( show_max, xm, 0 );
	}
	chrs_put( show_max, move_x, 0 );
	return trig ;
}

int scroll_y( int move_y )
{
	int	ym, pad, trig ;

	trig = 0 ;
	if( move_y == 0 ) return 0 ;
	for( ym = SGN( move_y, 16 ) ; 16 < ABS( move_y ) ; move_y -= ym ){
		SND_joy_in_2( 0, &pad ), trig |= ( ~pad & 0xf0 );
		chrs_put( show_max, 0, ym );
	}
	chrs_put( show_max, 0, move_y );
	return trig ;
}
