/******************************************************************/
/*
	スクロール スーパーコマンダー
	Ｉｍｐｒｏｖｅｄ １９９２−９３  ｂｙ  ＡＩＧ−ＳＯＦＴ
*/
/******************************************************************/
/* コンパイル定数 */

#define	_X68_	1	/* Ｘ６８フラグ */

/******************************************************************/

#include <stdio.h>
#include <string.h>
#include <time.h>

typedef unsigned char unchar;

#define ESC	0x1b
#define	SPC	' '
#define	CR	0x0d

/******************************************************************/
/* 汎用関数定義 */

#define printc(c)	fputc(c,stdout)		/* １文字表示 */
#define prints(s)	fputs(s,stdout)		/* 文字列表示 */
#define beep()		printc('\a')		/* ベル */
#define crlf()		printc('\n')		/* 改行 */
#define cls()		prints("\x1b[2J")	/* 画面クリア */
#define	curoff()	prints("\x1b[>5h");	/* カーソルオフ */
#define	curon()		prints("\x1b[>5l");	/* カーソルオン */
#define	eline()		prints("\x1b[0K");	/*カーソル以下行末までクリア*/
#define	syslineoff()	prints("\x1b[>1h");	/* システム行オフ */
#define	syslineon()	prints("\x1b[>1l");	/* システム行オン */

/* 専用関数定義 */
#define	rand2(seed)	(rand()%(seed))		/* 0〜seed-1の乱数発生 */
#define	vwait(t)	TWait(t*wtt)		/* ウエイト関数 */
#define	scrn(x,y)	(map[y][x])		/* マップを読み出す */

/* プロトタイプ宣言 */
long CalcWait();

/* 高速化定義 */
#if _X68_	/* X68 */
#define _FIRST_		1
#include <iocslib.h>
#define	locate(x,y)	B_LOCATE(x,y)
#define	cprint(c)	B_PUTC(c)
#define	sprint(s)	B_PRINT(s)
#else		/* MS-DOS(Turbo-C) */
#define _FIRST_		2
#include <conio.h>
#define	locate(x,y)	gotoxy((x)+1,(y)+1)
#define	cprint(c)	cprintf("%c",c)
#define	sprint(s)	cprintf(s)
#endif

/******************************************************************/
/* 定数定義 */

/* 画面幅 */
#define DX	80	/* 実画面ｘ幅 */
#define	DY	24	/* 実画面ｙ幅 */
#define WX	32	/* マップＸ幅 */
#define WY	32	/* マップＹ幅 */

/* 仮想画面内ゲームフィールド座標 */
#define HX	4		/* ホーム座標 */
#define HY	4
#define WF	25		/* フィールド幅：Ｘ，Ｙ同じ */
#define EX	(HX+WF-1)	/* エンド座標 */
#define EY	(HY+WF-1)

/* 移動方向定数 */
/* 移動方向：0=x+1 , 1=x-1 , 2=y+1 , 3=y-1 */
#define RIGHT	0
#define LEFT	1
#define DOWN	2
#define UP	3

/* リターン値定数 */
#define	READY		0	/* そのまま */
#define	MENCLEAR	1	/* 面クリア */
#define GAMEOVER	2	/* ゲームオーバー */
#define EXITOVER	3	/* 強制中断 */
#define ERROR		4	/* パラメーターチェックエラー */

#define EXITCUT		'!'	/* 強制中断キー */

/* キャラクター */
#define	FWAKU		'H' /* フィールド枠 */
#define	KABE1		'*' /* 壁１ */
#define	KABE2		'･' /* 壁２ */
#define	KABE3		'O' /* 壁３ */
#define	WAKU		'#' /* 外枠 */
#define	U_HITO		'A' /* 上向き人 */
#define	L_HITO		'<' /* 左向き人 */
#define	R_HITO		'>' /* 右向き人 */
#define	D_HITO		'V' /* 下向き人 */
#define	BOM		'B' /* 爆発 */
#define	LR_LAZER	'-' /* 人レーザー：横 */
#define	UD_LAZER	'|' /* 人レーザー：縦 */
#define	UALIEN		'$' /* うろつきエイリアン */
#define	MALIEN		'%' /* 周りエイリアン */
#define	RALIEN		'&' /* 回ってるエイリアン */
#define	BEAM		'+' /* 周りエイリアンビーム */

/* その他定数 */
#define MANS	5	/* 初期人数 */
#define ROUNDS	9	/* 周りエイリアン回る数 */
#define	ALIENS	36	/* 周りエイリアン初期数 */
#define RCMAX	2	/* 回りエイリアン動作カウンタ */

/* スクロール用定数 */
#define FX	14	/* フィールドサイズｘ */
#define FY	9	/* フィールドサイズｙ */
#define CHX	3	/* チップサイズｘ */
#define CHY	2	/* チップサイズｙ */
#define	OFX	5	/* 画面上フィールドホーム座標ｘ */
#define	OFY	5	/* 画面上フィールドホーム座標ｙ */

/* レーダー用定数 */
#define	RX	(OFX+FX*CHX+1)	/* レーダー座標ｘ */
#define	RY	OFY		/* レーダー座標ｙ */

/******************************************************************/
/* グローバル変数 */

int manx,many;		/* 人座標 */
int dman;		/* 人移動方向 */
unchar cman;		/* 人キャラクター */
int mans;		/* 人残り人数 */

int lx,ly;		/* 人レーザーの座標 */
int flazer;		/* レーザーフラグ */
int dlazer;		/* レーザー移動方向 */
unchar clazer;		/* レーザーキャラクター */

int maliens;		/* 周りエイリアン残り数 */
int ba;			/* 周りビーム出す順番 */
int bx,by;		/* 周りエイリアンビーム座標 */
int dbeam;		/* 周りエイリアンビーム移動方向 */
int fbeam;		/* 周りエイリアンビームフラグ */

int rx,ry;		/* 回りエイリアン座標 */
int dralien;		/* 回りエイリアン移動方向 */
int r;			/* 回りエイリアンの残り回る回数 */
int rcount;		/* 回りエイリアンは２回に一回動く */

int ux,uy;		/* うろつきエイリアン座標 */
int dualien;		/* うろつきエイリアン移動方向 */
int ccount;		/* うろつきエイリアン方向変換カウント */

int sco,hsc;		/* 得点 */
int pa;			/* 面数 */

int f1x,f1y;		/* 今のフィールドのホーム座標 in map */
int f2x,f2y;		/* 新しいフィールドのホーム座標 in map */

long	wtt;		/* ウエイト */

unchar map[WY+1][WX];	/* マップ : +1 for レーダー表示 */

/******************************************************************/

void main()
{
int ret;
	/* 初期化 */
	srand2(); /* 乱数初期化 */
	prints("ウエイト時間算出中...");
	wtt=CalcWait()/60; /* ウエイト算出(1/60s) */
	syslineoff();
	do {
		curoff(); /* cursor off */
		pa=0; /* 面数（最初に＋１するから）*/
		sco=0; /* 得点＝０ */
		mans=MANS; /* 人の残り人数 */
		
		do { /* 面ごとループ */
			pa++; /* 面＋１ */
			init_screen(); /* 画面初期化 */
			start();
			do { /* メインループ */
				/* 人動作 */
				if ((ret=man_move())!=READY) break;
				/* エイリアンビーム移動 */
				if ((ret=alian_beam())!=READY) break;
				vwait(6);
				/* 回りエイリアン移動 */
				if ((ret=round_alian_move())!=READY) break;
				/* うろつきエイリアン移動 */
				ret=urotuki_alian_move();
				/* 人レーザー移動 */
				if ((ret=lazer_move())!=READY) break;
				vwait(6);
			} while (ret==READY);
			/* 面クリアかゲームオーバー */
			if (ret==MENCLEAR) { /* 面クリアの時 */
				vwait(35);
				/* 残りラウンド数＋１００点される */
				while (r>0) {
					beep();
					score(10); /* +100点 */
					vwait(8);
					r--;
				}
			}
			vwait(35);
		} while (ret==MENCLEAR);
		if (ret==EXITOVER) { /* 強制中断 */
			curon();
			break;
		}
		vwait(35);

		/* ゲーム終了 */
		message("☆☆ ＧＡＭＥ　ＯＶＥＲ ☆☆",4);
		if (sco>hsc) {
			message("＊＊　新記録！！　＊＊",4);
			hsc=sco;
			hi_score();
			beep();
		}

		center("もう一度しますか？",16);
		curon();
		kbclr();
		do {
			ret=toupper(getch());
		} while (ret!='Y' && ret!='N' && ret!=ESC);
		ret=(ret=='Y');
	} while (ret);
	/* 正常終了ならret=0 : exit code */
	crlf();
	syslineon();
	exit(ret);
}

/******************************************************************/

init_screen()
/* 画面初期化＋α */
{
int x,y;
	clr_map();	/* 仮想テキストＶＲＡＭクリア */
	cls();		/* 実テキスト画面クリア */
	
	/* フィールド枠描画 */
	locate(OFX-1,OFY-1);
	for (x=0;x<=FX*CHX+1;x++) cprint(FWAKU);
	locate(OFX-1,OFY+FY*CHY);
	for (x=0;x<=FX*CHX+1;x++) cprint(FWAKU);
	
	for (y=OFY-1;y<=OFY+FY*CHY;y++) {
		locate(OFX-1,y); cprint(FWAKU);
		locate(OFX+FX*CHX,y); cprint(FWAKU);
	}

	man_init0();
	f1x=f2x; f1y=f2y;
	chip_scroll();
	
	title();	/* タイトル表示 */
	pattern();	/* パターン表示 */
	r=ROUNDS;	/* ラウンド＝９ */
	round();	/* 回りエイリアンの残り回る回数表示 */
	mans_left();	/* 残り人数表示 */
	flazer=0;
	
	/* 外枠 */
	for (x=0;x<WF;x++) { /* 横 */
		printxy(HX+x,HY,WAKU); /* 上 */
		printxy(HX+x,EY,WAKU); /* 下 */
	}
	for (y=0;y<WF;y++) { /* 縦 */
		printxy(HX,HY+y,WAKU); /* 左 */
		printxy(EX,HY+y,WAKU); /* 右 */
	}
	
	/* 内ブロック群 */
	for (x=HX+3;x<=EX-3;x++) { /* 横 */
		for (y=HY+3;y<=EY-3;y++) printxy(x,y,KABE1); /* 縦 */
	}
	
	/* ブロック加工 */
	switch (pa) {
		default:
			for (x=1;x<=17;x++) {
				printxy(HX+4,HY+3+x,KABE2);
				printxy(EX-4,HY+3+x,KABE2);
				printxy(HX+3+x,HY+4,KABE2);
				printxy(HX+3+x,EY-4,KABE2);
			}
		case 5:
			for (x=2;x<=16;x++) {
				printxy(HX+5,HY+3+x,KABE2);
				printxy(EX-5,HY+3+x,KABE2);
				printxy(HX+3+x,HY+5,KABE2);
				printxy(HX+3+x,EY-5,KABE2);
			}
		case 4:
			for (x=4;x<=14;x++) {
				printxy(HX+7,HY+3+x,KABE2);
				printxy(EX-7,HY+3+x,KABE2);
				printxy(HX+3+x,HY+7,KABE2);
				printxy(HX+3+x,EY-7,KABE2);
			}
		case 3:
			for (x=5;x<=13;x++) {
				printxy(HX+8,HY+3+x,KABE2);
				printxy(EX-8,HY+3+x,KABE2);
				printxy(HX+3+x,HY+8,KABE2);
				printxy(HX+3+x,EY-8,KABE2);
			}
		case 2:
			for (x=6;x<=12;x++) {
				printxy(HX+9,HY+3+x,KABE3);
				printxy(EX-9,HY+3+x,KABE3);
				printxy(HX+3+x,HY+9,KABE3);
				printxy(HX+3+x,EY-9,KABE3);
			}
		case 1:
			break;
	}
	
	/* 通路作成 */
	for (y=HY+6;y<=EY-6;y+=4) { /* 横 */
		for (x=HX+3;x<=EX-3;x++) printxy(x,y,SPC);
	}
	for (x=HX+6;x<=EX-6;x+=4) { /* 縦 */
		for (y=HY+3;y<=EY-3;y++) printxy(x,y,SPC);
	}
	
	/* 周りエイリアン */
	for (x=HX+4;x<=EX-4;x+=2) { /* 横 */
		printxy(x,HY+1,MALIEN);
		printxy(x,EY-1,MALIEN);
	}
	for (y=HY+4;y<=EY-4;y+=2) { /* 縦 */
		printxy(HX+1,y,MALIEN);
		printxy(EX-1,y,MALIEN);
	}
	maliens=ALIENS;	/* 周りエイリアン残り数 */
	fbeam=0;	/* 周りエイリアンビームフラグ */
	ba=0;		/* 周りエイリアンビーム出す順番 */
	
	/* その他表示 */
	man_init();		/* 人 */
	round_alien_init();	/* 回りエイリアン */
	urotuki_alien_init();	/* うろつきエイリアン */
}

/******************************************************************/

title()
/* タイトル表示 */
{
	center("＊＊　スーパーコマンダー　＊＊",0);
	score(0);
	hi_score();
}

score(int point)
/* 得点加算＆表示 */
{
	sco+=point;
	locate(7,1);
	printf("SCORE  :%05d0",sco); /* 下に表示されるPATTERNに合わせるため */
}

pattern()
/* 面数表示 */
{
	locate(7,2);
	printf("PATTERN:%d",pa);
}

hi_score()
/* ハイスコア表示 */
{
	locate(27,1);
	printf("HI-SCORE:%05d0",hsc);
}

mans_left()
/* 残り人数表示 */
{
int i;
	locate(27,2);
	prints("残り人数:");
	for (i=0;i<mans;i++) sprint("♀");
	sprint("  ");
}

round()
/* 回りエイリアンの残り回る回数表示 */
{
	locate(OFX+1,DY-1);
	printf("[ROUND:%d]",r);
}

/******************************************************************/

start()
/* スタート時間待ち処理 */
{
int t=3,x;
	vwait(23);
	if (pa==1) {
		/* 最初だけスタートカウント */
		x=(OFX+FX*CHX-5)/2;
		locate(x,DY);
		sprint("開始 ");
		do {
			locate(x+5,DY); printf("%d 秒前",t--);
			beep();
			vwait(60); /* 1sec */
		} while (t>0);
		
		locate(x,DY); sprint("開始！！"); eline();
		bell(5);
		locate(x,DY); eline();
		vwait(23);
	}
	kbclr();
}

/******************************************************************/

man_init()
/* 人初期化 */
{
	cman=R_HITO;
	dman=RIGHT;
	printxy(manx,many,cman);
}

man_init0()
/* 人初期化０ */
{
	manx=HX+12;
	many=HY+14;
	f2x=manx-FX/2;	/* 初期フィールド座標 */
	f2y=many-FY/2;
}

round_alien_init()
/* 回りエイリアン初期化 */
{
	rx=HX+3; /* ホーム＋１ */
	ry=HY+2;
	dralien=RIGHT;
	rcount=0;
	printxy(rx,ry,RALIEN);
}

urotuki_alien_init()
/* うろつきエイリアン初期化 */
{
	ux=HX+6;
	uy=HY+6;
	dualien=urotuki_alien_direc(-1);
	printxy(ux,uy,UALIEN);
}

/******************************************************************/

int alian_beam()
/* 周りエイリアンビーム */
{
int x,y,c;
	if (fbeam) { /* すでにビームは出ている */
		/* 座標待避 */
		x=bx;
		y=by;
		
		printxy(x,y,SPC); /* 元の場所を消す */
		switch (dbeam) { /* 移動 */
			case RIGHT: x++; break;
			case LEFT:  x--; break;
			case DOWN:  y++; break;
			case UP:    y--; break;
		}
		/* 移動先チェック */
		switch (scrn(x,y)) {
			/* 移動先が空間でない時１ */
			case KABE3:/* ビームがすり抜ける壁 */
				switch (dbeam) { /* すり抜け処理 */
					case RIGHT: x++; break;
					case LEFT:  x--; break;
					case DOWN:  y++; break;
					case UP:    y--; break;
				}
				/* 後はそのまま移動可能 */
			
			/* 移動先は空間 */
			case SPC: /* そのまま移動可能 */
				bx=x;
				by=y;
				printxy(bx,by,BEAM); /* 新しい場所に描く */
				return(READY);
			
			/* 移動先が空間でない時２ */
			case KABE1:/* すぐ消える壁 */
				printxy(x,y,SPC); /* 壁を消す */
				break;
			case KABE2:/* ２段階で消える壁 */
				printxy(x,y,KABE1); /* 壁１にする */
				break;
			
			case LR_LAZER: /* 人レーザー */
			case UD_LAZER:
				printxy(x,y,SPC); /*人ﾚｰｻﾞｰを消す:打消し合う*/
				flazer=0;
				break;
			
			case U_HITO: /* 人に当たった */
			case D_HITO:
			case L_HITO:
			case R_HITO:
				c=man_dead(x,y);
				if (c==GAMEOVER) return(c); /* GAME OVER */
		} /* そのほかの時は消すだけ */
		fbeam=0;
		return(READY);
	}
	/* ビームを出す */
	
	/* 順番＋１ */
	ba++; /* 次の番ですよ */
	if (ba>=ALIENS) ba=0; /* ぐるっと回る */
	
	/* その順番の周りエイリアンは存在しているか */
	c=ba%(ALIENS/4); /* その辺の何番目か：０〜８（＝ＡＬＩＥＮＳ／４）*/
	switch (ba/(ALIENS/4)) { /* その番号のｴｲﾘｱﾝは４つの辺のどこにいるか */
		case 0:	/* 上 */
			x=HX+4+c*2;
			y=HY+1;
			bx=x;
			by=y+1;
			dbeam=DOWN;
			break;
		case 1:	/* 右 */
			x=EX-1;
			y=HY+4+c*2;
			bx=x-1;
			by=y;
			dbeam=LEFT;
			break;
		case 2:	/* 下 */
			x=EX-4-c*2;
			y=EY-1;
			bx=x;
			by=y-1;
			dbeam=UP;
			break;
		case 3:	/* 左 */
			x=HX+1;
			y=EY-4-c*2;
			bx=x+1;
			by=y;
			dbeam=RIGHT;
			break;
	}
	if (scrn(x,y)!=MALIEN) return(READY); /* そこに周りｴｲﾘｱﾝはいない */
	
	/* エイリアンは存在するのでビームを出す */
	/* ビームの発射先検査：存在しないはずのものはチェックしない */
	switch (scrn(bx,by)) {
		case SPC:
			fbeam=1;
			printxy(bx,by,BEAM);
			break;
		
		case LR_LAZER: /* 人レーザー */
		case UD_LAZER:
			printxy(bx,by,SPC); /* 人レーザーを消す：打消し合う */
			flazer=0;
			break;
	}
	return(READY);
}

/******************************************************************/

int urotuki_alian_move()
/* うろつきエイリアン移動 */
{
int x,y,c;
	if (ccount==0) dualien=urotuki_alien_direc(dualien);
	
	/* 座標待避 */
	x=ux;
	y=uy;
	
	printxy(x,y,SPC); /* 元の場所を消す */
	switch (dualien) { /* 移動 */
		case RIGHT:if (x<EX-3) x++; break;
		case LEFT: if (x>HX+3) x--; break;
		case DOWN: if (y<EY-3) y++; break;
		case UP:   if (y>HY+3) y--; break;
	}
	/* 移動先チェック */
	c=scrn(x,y);
	if (c==SPC) { /* そのまま移動可能 */
		ux=x;
		uy=y;
	} else {
		if (c==U_HITO||c==D_HITO||c==L_HITO||c==R_HITO) {
			/* 人に当たった */
			c=man_dead(x,y);
			if (c==GAMEOVER) return(c); /* GAME OVER */
			urotuki_alien_init();
			return(READY);
		}
		/* それ以外の時は動かない */
	}
	
	printxy(ux,uy,UALIEN); /* 新しい場所に描く */
	ccount--; /* 方向変換カウント−１ */
	return(READY);
}

/******************************************************************/

int urotuki_alien_direc(int direc)
/* うろつきエイリアン方向設定 */
/* return: 0〜3 : 方向 */
{
int d,i=0,ch[4];
	/* 周りの状態把握：最低１ヶ所は空いているはず */
	if (ux<EX-3 && !check_kabe(scrn(ux+1,uy))) ch[i++]=RIGHT; /* RIGHT */
	if (ux>HX+3 && !check_kabe(scrn(ux-1,uy))) ch[i++]=LEFT;  /* LEFT */
	if (uy<EY-3 && !check_kabe(scrn(ux,uy+1))) ch[i++]=DOWN;  /* DOWN */
	if (uy>HY+3 && !check_kabe(scrn(ux,uy-1))) ch[i++]=UP;	  /* UP */
	
	d=ch[rand2(i)];
	/* 正反対の方向に動こうとする時は一度考え直す */
	if ((direc==RIGHT&&d==LEFT)||(direc==LEFT&&d==RIGHT)
	  ||(direc==DOWN &&d==UP)  ||(direc==UP  &&d==DOWN)) d=ch[rand2(i)];
	
	/* 方向変換カウント */
	ccount=rand2(3)+2; /* 数歩ごとに方向変換する */
	return(d); /* 0〜3 */
}

/******************************************************************/

int check_kabe(int c)
/* 壁チェック */
/* return : 0=壁でない , 1=壁 */
{
	return(c==KABE1 || c==KABE2 || c==KABE3);
}

/******************************************************************/

int round_alian_move()
/* 回りエイリアン移動 */
{
	rcount++;
	if (rcount<RCMAX) return(READY); /* 動かない */
	rcount=0;
	
	/* 角での方向変換 */
	if (ry==HY+2 && rx==EX-2) dralien=DOWN;
	if (ry==EY-2 && rx==EX-2) dralien=LEFT;
	if (ry==EY-2 && rx==HX+2) dralien=UP;
	if (ry==HY+2 && rx==HX+2) { /* ホーム：１周した */
		dralien=RIGHT;
		r--;
		round();
		if (r==0) return(GAMEOVER); /* ラウンド＝０：ゲームオーバー */
	}
	printxy(rx,ry,SPC); /* 元の場所を消す */
	switch (dralien) { /* 移動 */
		case DOWN:  ry++; break;
		case LEFT:  rx--; break;
		case UP:    ry--; break;
		case RIGHT: rx++; break;
	}
	printxy(rx,ry,RALIEN); /* 新しい場所に描く */
	return(READY);
}

/******************************************************************/

int lazer_move()
/* 人のレーザーの移動 */
{
int ch;
	if (!flazer) return(READY); /* レーザーは出ていない */
	printxy(lx,ly,SPC); /* 元の位置を消す */
	switch (dlazer) {
		case RIGHT:lx++; break;
		case LEFT: lx--; break;
		case DOWN: ly++; break;
		case UP:   ly--; break;
	}
	/* 飛び先チェック */
	ch=scrn(lx,ly);
	if (ch==SPC) { /* 何もないのでそのまま飛ばす */
		printxy(lx,ly,clazer);
		return(READY);
	}
	/* 飛び先に何かあった */
	flazer=0; /* レーザーを消す */
	return(hit_lazer(lx,ly,ch));
}

/******************************************************************/

int hit_lazer(int lx,int ly,int ch)
/* レーザーあたり判定 */
{
	switch (ch) {
		case MALIEN: /* 周りエイリアン */
			printxy(lx,ly,SPC); /* 周りエイリアンも消す */
			beep();
			score(3); /* +30点 */
			if (--maliens==0) return(MENCLEAR); /* 面クリア */
			break;
		case RALIEN: /* 回りエイリアン */
			printxy(lx,ly,SPC); /* 回りエイリアンも消す */
			beep();
			score(5); /* +50点 */
			r--; /* ラウンド数が１つ減る */
			round();
			if (r==0) return(GAMEOVER); /* ﾗｳﾝﾄﾞ=0 -> ｹﾞｰﾑｵｰﾊﾞｰ */
			round_alien_init();
			break;
		case UALIEN: /* うろつきエイリアン */
			printxy(lx,ly,SPC); /* うろつきエイリアンも消す */
			beep();
			sco=0; /* 得点が０になる */
			score(0);
			urotuki_alien_init();
			vwait(18);
			beep();
			break;
		case BEAM: /* エイリアンビーム */
			printxy(lx,ly,SPC); /* エイリアンビームも消す */
			fbeam=0;
			break;
	} /* その他の時はなにもしない */
	return(READY);
}

/******************************************************************/

int man_move()
/* 人の動作 */
{
int x,y;
	/* 座標待避 */
	x=manx;
	y=many;
	
	switch (getky()) { /* キー入力 */
		case 0: /* キー入力が無し：なにもしない */
			return(READY);
		case EXITCUT: /* 強制中断 */
			return(EXITOVER);
		
		/* レーザー */
		case SPC:
		case '5':
			return(man_lazer());
		
		/* 移動 */
		case '8':/* 上 */
			if (y==HY+3 || scrn(x,y-1)!=SPC) return(READY);
			if ((dman==LEFT && cman==L_HITO)
				||(dman==RIGHT && cman==R_HITO)) {
					/* 前向き */
					cman=U_HITO;
			}
			else
			if ((dman==LEFT && cman==R_HITO)
				||(dman==RIGHT && cman==L_HITO)) {
					/* 後ろ向き */
					cman=D_HITO;
			}
			dman=UP;
			many--;
			if (f1y>0) f2y=f1y-1;
			break;
		case '2':/* 下 */
			if (y==EY-3 || scrn(x,y+1)!=SPC) return(READY);
			if ((dman==LEFT && cman==L_HITO)
				||(dman==RIGHT && cman==R_HITO)) {
					/* 前向き */
					cman=D_HITO;
			}
			else
			if ((dman==LEFT && cman==R_HITO)
				||(dman==RIGHT && cman==L_HITO)) {
					/* 後ろ向き */
					cman=U_HITO;
			}
			dman=DOWN;
			many++;
			if (f1y<WY+FY) f2y=f1y+1;
			break;
		case '4':/* 左 */
			if (x==HX+3 || scrn(x-1,y)!=SPC) return(READY);
			if ((dman==UP && cman==U_HITO)
				||(dman==DOWN && cman==D_HITO)) {
					/* 前向き */
					cman=L_HITO;
			}
			else
			if ((dman==UP && cman==D_HITO)
				||(dman==DOWN && cman==U_HITO)) {
					/* 後ろ向き */
					cman=R_HITO;
			}
			dman=LEFT;
			manx--;
			if (f1x>0) f2x=f1x-1;
			break;
		case '6':/* 右 */
			if (x==EX-3 || scrn(x+1,y)!=SPC) return(READY);
			if ((dman==UP && cman==U_HITO)
				||(dman==DOWN && cman==D_HITO)) {
					/* 前向き */
					cman=R_HITO;
			}
			else
			if ((dman==UP && cman==D_HITO)
				||(dman==DOWN && cman==U_HITO)) {
					/* 後ろ向き */
					cman=L_HITO;
			}
			dman=RIGHT;
			manx++;
			if (f1x<WX+FX) f2x=f1x+1;
			break;
	}
	if (x!=manx || y!=many) { /* 動いた時だけ */
		/* 移動 */
		if (f1x!=f2x || f1y!=f2y) chip_scroll();
		/* 前の人を消す */
		printxy(x,y,SPC);
		/* 人の表示 */
		printxy(manx,many,cman);
	}
	return(READY);
}

/******************************************************************/

int man_lazer()
/* 人レーザー発射処理 */
{
int ch;
	if (flazer) { /* すでにレーザーが出ている時 */
		beep();
	} else { /* 出ていない時 */
		/* レーザーは人の向いている方向に飛ぶ */
		/* レーザー発射先チェック */
		lx=manx; ly=many; /* レーザー初期座標 */
		switch (cman) {
			case R_HITO:
				lx++;
				dlazer=RIGHT;
				clazer=LR_LAZER;
				break;
			case L_HITO:
				lx--;
				dlazer=LEFT;
				clazer=LR_LAZER;
				break;
			case D_HITO:
				ly++;
				dlazer=DOWN;
				clazer=UD_LAZER;
				break;
			case U_HITO:
				ly--;
				dlazer=UP;
				clazer=UD_LAZER;
				break;
		}
		ch=scrn(lx,ly);
		if (ch!=SPC) { /* 何かある */
			/* レーザーを描く前に即判定する */
			return(hit_lazer(lx,ly,ch));
		}
		/* レーザー発射先には何もない */
		printxy(lx,ly,clazer);
		flazer=1; /* 以後はlazer_move()で移動させる */
	}
	return(READY);
}

/******************************************************************/

int man_dead(int x,int y)
/* 人がやられた処理 */
{
	beep();
	printxy(x,y,BOM);
	vwait(18);
	beep();
	mans--;
	mans_left();
	if (mans==0) return(GAMEOVER); /* GAME OVER */
	printxy(x,y,SPC);
	man_init0();
	man_init();
	chip_scroll();
	beep();
	return(READY);
}

/******************************************************************/

int getky()
/* キー入力 */
{
int c;
	if (!kbhit()) return(0);
	c=getch();
	if (c==ESC) { /* PAUSE */
		curon();
		center("ＰＡＵＳＥ",DY);
		c=getch();
		center("          ",DY);
		curoff();
		if (c!=EXITCUT) c=0; /* 強制中断以外は無効 */
	}
	kbclr();
	return(c);
}

/******************************************************************/

center(unchar *mes,int y)
/* メッセージセンタリング表示 */
{
int x;
	x=(OFX+FX*CHX-strlen(mes))/2; /* センタリング */
	locate(x,y);
	sprint(mes);
}

/******************************************************************/

message(unchar *mes,int tim)
/* メッセージを指定回数点滅表示する */
{
int i,y;
unchar line[DX];
	for (i=0;i<strlen(mes);i++) line[i]=SPC;
	line[i]=0;
	y=OFY+(FY*CHY-OFY)/2;
	for (i=0;i<tim;i++) {
		center(mes,y);
		vwait(20);
		center(line,y);
		beep();
		vwait(20);
	}
}

/******************************************************************/

printxy(int x,int y,int c)
/* マップ出力＆レーダー表示 */
{
int cc;
	/* マップに出力 */
	map[y][x]=c;
	
	if (x>=f1x && x<f1x+FX && y>=f1y && y<f1y+FY) {
		/* 表示領域の時は表示も行なう */
		prchip(x-f1x,y-f1y,c);
	}
	
	/* レーダー表示 */
	if (y&1) { /* 上と合成 */
		cc=map[y-1][x];
	} else { /* 下と合成 */
		cc=c;
		c=map[y+1][x];
	}
	/*   上        下 */
	if (cc!=SPC && c!=SPC) c=':';
	if (cc!=SPC && c==SPC) c='\'';
	if (cc==SPC && c!=SPC) c='.';
	/* cc==SPC && c==SPC -> c=SPC */
	
	locate(RX+x,RY+y/2);
	cprint(c);
}

/******************************************************************/

prchip(int x,int y,int c)
/* チップ表示 */
{
int i,j;
char *s;
static unchar ss[CHX+1]; /* 00で初期化される */
	/* キャラクター変換 */
	switch (c) {
		default      :s="012345"; break; /* デバッグ用：有り得ない */
		case SPC     :s="      "; break; /* クリア */
		case WAKU    :s="######"; break; /* 外枠 */
		case KABE1   :s="******"; break; /* 壁１ */
		case KABE2   :s="OOOOOO"; break; /* 壁２ */
		case KABE3   :s="･･････"; break; /* 壁３ */
		case MALIEN  :s="<A><V>"; break; /* 周りエイリアン */
		case RALIEN  :s="___) ("; break; /* 回ってるエイリアン */
		case UALIEN  :s="Y_Y>-<"; break; /* うろつきエイリアン */
		case U_HITO  :s="_A_[_]"; break; /* 上向き人 */
		case L_HITO  :s=" __<_]"; break; /* 左向き人 */
		case R_HITO  :s="__ [_>"; break; /* 右向き人 */
		case D_HITO  :s="[~]~V~"; break; /* 下向き人 */
		case BOM     :s="X_XX~X"; break; /* 爆発 */
		case LR_LAZER:s="___~~~"; break; /* 人レーザー：横 */
		case UD_LAZER:s=" |  | "; break; /* 人レーザー：縦 */
		case BEAM    :s="_|_~|~"; break; /* 周りエイリアンビーム */
	}
	
	/* チップ表示 */
	x=x*CHX+OFX;
	y=y*CHY+OFY;
	for (j=0;j<CHY;j++) {
		for (i=0;i<CHX;i++) ss[i]=*s++;
		locate(x,y+j);
		sprint(ss);
	}
}

/******************************************************************/

clr_map()
/* マップクリア */
{
int x,y;
	for (y=0;y<WY;y++) {
		for (x=0;x<WX;x++) map[y][x]=SPC;
	}
}

/******************************************************************/

chip_scroll()
/* チップスクロール */
{
int x,y;
unchar c;
	for (x=0;x<FX;x++) {
		for (y=0;y<FY;y++) {
			c=map[f2y+y][f2x+x];
			if (c!=map[f1y+y][f1x+x]) {
				/* 移動前後のフィールド内容を比較し、
				   違うところのみ書き直す */
				prchip(x,y,c);
			}
		}
	}
	f1x=f2x;
	f1y=f2y;
}

/******************************************************************/
/* 汎用関数 */
/******************************************************************/

srand2()
/* rand()乱数を初期化する */
{
time_t tm;
	time(&tm);
	tm&=0x0fff;
	tm*=16;
	srand(tm);
}

/******************************************************************/

kbclr()
/* キーボードバッファークリア */
{
	while (kbhit()) getch();
}

/******************************************************************/

long CalcWait()
/* ウエイト量自動算出 */
{
time_t tim,tm;
long count;
	/* ０クロックチェック */
	time(&tm);
	do {
		time(&tim);
	} while (tim-tm==0);
	count=0L;
	do {
		time(&tm);
		count++;
	} while (tm-tim==0);
	return(count); /* １秒に必要なカウント数 */
}

/******************************************************************/

TWait(long wt)
/* ウエイト */
{
long i;
time_t tm;
	for (i=0;i<wt;i++) time(&tm);
}

/******************************************************************/

bell(int t)
/* 指定回数ベル鳴らし */
{
	do {
		beep();
		vwait(1);
	} while (--t>0);
}

/******************************************************************/
