/****************************************************************
	Map panel data generator for CAR RACE  version 1.10
		  Programmed by Y.Nishida
					[ Apr.10, 1990 ]
 ****************************************************************/

#include	<stdio.h>
#include	<memory.h>
#include	<strings.h>

#define		unchar		unsigned char
#define		unshort		unsigned short
#define		TRUE		1
#define		FALSE		0
#define		PNLTOP		1
#define		PNLNXT		0
#define		LNKBTM		-1
#define		MAXPNL		0x3000

typedef	struct	{
		short	flg ;
		short	lnk ;
		short	btm ;
		short	len ;
	} arptr ;

arptr	pnlptr[MAXPNL] ;		/* panel pointer	*/
unshort	pnlofs[MAXPNL] ;		/* panel offset address	*/
unchar	pnlbuf[MAXPNL][4] ;		/* panel buffer		*/
int	pnllen  = 0 ;			/* panel data length	*/
int	pnlcnt  = 0 ;			/* panel counter	*/
int	clrcode = 0 ;			/* clear code		*/


main( argc,argv )
int	argc ;
char	**argv ;
{
	FILE	*tp ;
	char	tbl_name[65] ;
	char	srn_name[65] ;
	char	pnl_name[65] ;
	char	pck_name[65] ;
	int	ct = 1 ;

	puts( "Map panel data generator for CAR RACE  version 1.10" ) ;
	if ( argc != 2 && argc != 3 ) {
		fputs( "usage: mkpanel <map name> [clear code]\n",stderr ) ;
		exit( 1 ) ;
	}
	strcpy( tbl_name,*(++argv)) ;
	strcat( tbl_name,".TBL" ) ;
	if (( tp = fopen( tbl_name,"r" )) == NULL ) {
		perror( tbl_name ) ;
		exit( 1 ) ;
	}
	if ( argc == 3 )  clrcode = atoi( *(argv+1)) & 0xff ;

	while ( fgets( srn_name,60,tp ) != NULL ) {
		if ( srn_name[0] != '#' && srn_name[0] != '\n' ) {
			set_sname( srn_name ) ;
			mkpanel( ct++,srn_name ) ;	/*  make panel data	*/
		}
	}
	fclose( tp ) ;

	prspnl() ;				/* compress panel data	*/
	if ( pnllen > 0x8000 ) {
		printf( "panel data size over. ( size=$%05x )\n", pnllen ) ;
		exit( 1 ) ;
	}
	strcpy( pck_name,*argv ) ;
	strcat( pck_name,".PCK" ) ;
	genpck( pck_name ) ;			/* generate panel check file	*/

	strcpy( pnl_name,*argv ) ;
	strcat( pnl_name,".PNL" ) ;
	genpnl( pnl_name ) ;			/* ganerate panel data file	*/

	exit( 0 ) ;
}

/******* set screen file name ***********************************/

set_sname( ss )
char	*ss ;
{
	while ((*ss != '\0') && (*ss != '\n')) ss++ ;
	strcpy( ss,".SCR" ) ;
}

/****************************************************************/
/*	Make panel data from screen file			*/
/****************************************************************/

mkpanel( nn,fname )
int	nn ;
char	*fname ;
{
	FILE	*rp ;
	unchar	redbuf[0x2300],pnldat[4] ;
	int	pnn ;
	register int	pct,sct,rct ;
	register unchar	*pnl,*dat ;

	if (( rp = fopen( fname,"r" )) == NULL ) {
		perror( fname ) ;
		exit( 1 ) ;
	}
	pnn = pnlcnt ;
	pnl = pnldat ;

	printf( "%2d screen file \"%s\"\t", nn,fname ) ; 
	fread( redbuf,sizeof(unchar),0x2300,rp ) ;
	chkclr( redbuf ) ;

	dat = redbuf ;
	for ( rct=0 ; rct<4 ; rct++ ) {
		for ( sct=0 ; sct<16 ; sct++ ) {
			for ( pct=0 ; pct<16 ; pct++ ) {
				*(pnl+0) = *(dat+ 0) ;
				*(pnl+1) = *(dat+64) ;
				*(pnl+2) = *(dat+ 2) ;
				*(pnl+3) = *(dat+66) ;
				dat += 4 ;
				setpnl( pnldat ) ;
			}
			dat += 64 ;
		}
	}
	fclose( rp ) ;
	printf( "create %4d panel(s)\n", pnlcnt-pnn ) ;
}

/*******  check clear code **************************************/

chkclr( buf )
unchar	*buf ;
{
	static	 int	ofs[4] = { 0x2100,0x2104,0x2200,0x2204 } ;
	register unchar	*da,*fg ;
	register int	cd,i,j,k,nn ;

	for ( da=buf,nn=0 ; nn<4 ; nn++ ) {
		fg = buf + ofs[nn] ;

		for ( i=0 ; i<32 ; i++ ) {
			for ( j=0 ; j<4 ; j++ ) {
				cd = *fg++ ;
				for ( k=0 ; k<8 ; k++ ) {
					if ( !(cd & 0x80)) *da = (unchar)clrcode ;
					cd <<= 1 ;
					da  += 2 ;
				}
			}
			fg += 4 ;
		}
	}
}

/*******  set panel data into panel buffer **********************/

setpnl( pnl )
unchar	*pnl ;
{
	register int	pnum ;

	if ( pnlcnt == 0 ) {
		memcpy( pnlbuf[pnlcnt++],pnl,sizeof(unchar)*4 ) ;
		return ( 0 ) ;
	}

	if (( pnum = cmppnl( pnlbuf,pnl,pnlcnt )) < pnlcnt ) return ( pnum ) ;
	if ( pnlcnt == MAXPNL ) {
		fputs( "panel data buffer over.\n",stderr ) ;
		exit( 1 ) ;
	}
	memcpy( pnlbuf[pnlcnt++],pnl,sizeof(unchar)*4 ) ;
	return ( pnum ) ;
}

/****************************************************************/
/*	Compress panel data					*/
/****************************************************************/

prspnl()
{
	register int	ct,ln ;

	int_pnpt() ;			/*  initialize panel pointer	*/

	for ( ln=3 ; ln>0 ; ln-- ) {
		printf( "compless %d character(s)\n",ln ) ;
		for ( ct=0 ; ct<pnlcnt ; ct++ ) {
			if ( pnlptr[ct].flg == PNLTOP ) {
				fit_panel( ln,ct ) ;
			}
		}
	}
	st_pnofs() ;
	printf( "compress ratio %2d%%\n", (pnllen*100)/(pnlcnt*4)) ;
}

/******* search fitted panel ************************************/

fit_panel( ln,sc )
int	ln,sc ;
{
	register arptr	*sp,*dp,*bp ;
	register int	dc ;

	sp = &pnlptr[sc] ;
	dp = pnlptr ;

	for ( dc=0 ; dc<pnlcnt ; dp++,dc++ ) {
		if ( sc != dc && dp->flg == PNLTOP ) {
			if ( !memcmp( pnlbuf[sc],&pnlbuf[dp->btm][4-ln],sizeof(unchar)*ln )) {
				bp = &pnlptr[dp->btm] ;
				bp->lnk = sc ;
				bp->len = 4-ln ;
				dp->btm = sp->btm ;
				sp->flg = PNLNXT ;
				break ;
			}
		}
	}
}

/******* initialize panel pointer *******************************/

int_pnpt()
{
	register arptr	*p ;
	register int	i ;

	for ( p=pnlptr,i=0 ; i<pnlcnt ; p++,i++ ) {
		p->flg = PNLTOP ;
		p->lnk = LNKBTM ;
		p->btm = i ;
		p->len = 4 ;
	}
}

/******* set panel offset ***************************************/

st_pnofs()
{
	register int	 ct,nn ;
	register unshort adrs = 0 ;

	for ( ct=0 ; ct<pnlcnt ; ct++ ) {
		if ( pnlptr[ct].flg == PNLTOP ) {
			nn = ct ;
			while ( nn != LNKBTM ) {
				pnlofs[nn]  = adrs ;
				adrs       += pnlptr[nn].len ;
				nn          = pnlptr[nn].lnk ;
			}
		}
	}
	pnllen = adrs ;
}

/****************************************************************/
/*	Generate panel check file				*/
/****************************************************************/

genpck( fname )
char	*fname ;
{
	FILE	*wp ;
	int	ct,nn,i ;

	if (( wp = fopen( fname,"w" )) == NULL ) {
		perror( fname ) ;
		exit( 1 ) ;
	}
	fwrite( &clrcode,sizeof(    int),     1,wp ) ;
	fwrite( &pnlcnt ,sizeof(    int),     1,wp ) ;
	fwrite( &pnllen ,sizeof(    int),     1,wp ) ;
	fwrite(  pnlofs ,sizeof(unshort),pnlcnt,wp ) ;

	for ( ct=0 ; ct<pnlcnt ; ct++ ) {
		if ( pnlptr[ct].flg == PNLTOP ) {
			nn = ct ;
			while ( nn != LNKBTM ) {
				for ( i=0 ; i<pnlptr[nn].len ; i++ ) {
					fputc( pnlbuf[nn][i], wp ) ;
				}
				nn = pnlptr[nn].lnk ;
			}
		}
	}
	fclose( wp ) ;
}

/****************************************************************/
/*	Generate panel data file				*/
/****************************************************************/

genpnl( fname )
char	*fname ;
{
	FILE	*wp ;
	int	ct,nn,i ;

	if (( wp = fopen( fname,"w" )) == NULL ) {
		perror( fname ) ;
		exit( 1 ) ;
	}
	for ( ct=0 ; ct<pnlcnt ; ct++ ) {
		if ( pnlptr[ct].flg == PNLTOP ) {
			nn = ct ;
			while ( nn != LNKBTM ) {
				for ( i=0 ; i<pnlptr[nn].len ; i++ ) {
					fputc( pnlbuf[nn][i], wp ) ;
				}
				nn = pnlptr[nn].lnk ;
			}
		}
	}
	fclose( wp ) ;
	printf( "total %d panels write.  ( size=$%05x )\n", pnlcnt,pnllen ) ;
}
