/******************************************************************/
//	レーダースネーキー −ＰＲＯ６８Ｋ
//		ＷＩＣＳ・ＢＡＳＥプログラム集よりの移植
//  Ａｒｒａｎｅｄ　１９９７  ｂｙ  ＡＩＧ−ＳＯＦＴ
/******************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	// exit
#include <process.h>
#include <ctype.h>
#include <conio.h>
#include <jfctype.h>
#include <iocslib.h>
#include <audio.h>
#include "defines.h"
#include "doslibm.h"
#include "aigtext.h"
#include "amacro.h"
#include "ascreen.h"
#include "astdio.h"
#include "aenv.h"
#include "await.h"
#include "anum.h"
#include "abuff.h"
#include "font.h"
#include "akey.h"
#include "skey.h"

char prog[]="@@> RS.C : 1998/01/16 FRI : GAME : Rader_Snaky";

// 97/11/02 : 初版
// 97/11/09 : 画面モード強制変更(ファイラーからの直接起動対応)
// 97/11/11 : 画面表示の高速化、PANIC後にレーダー表示が出るようにする(不完全)
// 97/11/12 : さらに画面表示高速化、角で蛙が画面外に出るバグ修正
// 97/11/13 : 蛙がまだ残っているのに面クリアするバグ修正
// 98/01/16 : PAUSE中も'!'でexit出来るようにする
/******************************************************************/
/* 定数定義 */

#define RECHIGH	"RS.HSC"	/* ハイ・スコア ファイル名 */

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

unchar *exec;			/* PANIC 起動プログラム */

/******************************************************************/
/* 定数＆変数定義 */

#define GWX	96		/* 実画面横幅 */
#define GWY	31		/* 実画面縦幅 */
#define WX	40		/* ゲーム画面横幅 */
#define WY	25		/* ゲーム画面縦幅 */
// ゲームキャラクターの表示は全て全角なので、画面幅はGWX/2
#define	CX	((GWX/2-WX)/2*2)	/* ゲーム画面を実画面の真ん中に持ってくる */
#define	CY	((GWY-WY)/2)		/* ゲーム画面を実画面の真ん中に持ってくる */

#define	FWX	33		// フィールドｘ幅
#define	FWY	29		// フィールドｙ幅
#define	FHX	4		// フィールドホームｘ座標
#define	FHY	4		// フィールドホームｙ座標
#define	FEX	0x1c		// フィールドエンドｘ座標
#define	FEY	0x19		// フィールドエンドｙ座標
#define	FHOME	(FHX+FHY*FWX)	// フィールドホームアドレス
unchar	SCWorkA[FWX*FWY];	// 仮想画面＝フィールド
int	adr;			// 仮想画面内の投影アドレスホーム

// 仮想画面内のキャラクターコード
#define	KABE	'#'		// 壁
#define	DOU	'o'		// 蛇の胴体
#define	KAO	'@'		// 蛇の顔
#define	KAO2	(KAO+1)		// 蛇の顔(別向き)
#define	KAERU	'$'		// 蛙

#define	TWX	9		// 一度に表示する仮想画面内のｘ幅
#define	TWY	8		// 一度に表示する仮想画面内のｙ幅
#define	T1X	3		// １キャラクター表示サイズｘ
#define	T1Y	3		// １キャラクター表示サイズｙ

int	hsc,sco;		// 得点
int	round;			// 面数
int	v[]={-FWX,-1,FWX,1};	// 方向別アドレス増分:上左下右
int	die;			// 終わりフラグ

// 蛇関係の変数
#define	SDPL	2		// 蛇のドット表示プレーン+1（黄色）
int	xx,yy,ox,oy,sx,sy;	// dot座標:頭、尾、？
int	mo;			// レーダーでの尻尾の点滅
int	muki,sipo;		// 頭の向き、尻尾位置
int	tan;			// 舌の状態
int	oto;			// 鳴らす音の種類
				// 0=音無し , 1=蛙を食べる音 , 2=向きを変える音
// 蛙関係の変数
#define	KMAX	5		// 蛙の数
#define	KDPL	1		// 蛙のドット表示プレーン+1（水色）
int	eat;			// 食べてない蛙の数
int	ici[KMAX];		// 仮想画面内アドレス
int	ix[KMAX],iy[KMAX];	// 移動先座標（ドット表示）
int	rx[KMAX],ry[KMAX];	// 現在座標（ドット表示）
int	der[KMAX],td[KMAX];	// 移動方向、食べられたかどうか
int	non;			// 蛙が自分から蛇に食べられた数＝蛇の胴体の伸びる長さ

// ADPCM用変数
unchar	*PCMrhiq,*PCMappl,*PCMhiq,*PCMpack;
int	 LENrhiq, LENappl, LENhiq, LENpack;

#define	MZ_LOCATE(x,y)	B_LOCATE(CX+(x)*2,CY+(y))

/******************************************************************/
// 汎用的ルーチン
/******************************************************************/

void WaitPCM()
{
	while (a_stat()); // 音が止まるまで待つ
}

void PCMplay(unchar *pcm,int len,int fq)
// ADPCMを鳴らす
{
	if (len>0) {
	    int f=0;
		if (fq<0) {f=1; fq=-fq;}
		a_play(pcm,len,fq,3,len);
		if (!f) WaitPCM(); // 音が止まるまで待つ
	}
}

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

int center(int y,unchar *mes)
// メッセージをセンタリングで表示
{
int x;
	x=(GWX-strlen(mes))/2; /* センタリング */
	B_LOCATE(x,y+CY);
	B_PRINT(mes);
	return(x);
}

void message(unchar *mes,int tim)
/* メッセージを指定回数点滅表示する */
{
int i,x;
	x=(GWX-strlen(mes))/2; /* センタリング */
	for (i=0;i<tim;i++) {
		B_LOCATE(x,GWY/2); B_PRINT(mes);
		vwait(20);
		B_LOCATE(x,GWY/2); eline();
		beep();
		vwait(20);
	}
}

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

void plot(int x,int y,int mode,int pl)
// セミグラフィック
// mode : 0=off, 1=on
// pl   : 1=水色 , 2=黄色 
{
static struct FNTBUF SemiG[]={
{ 8, 8,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},	// OFF
{ 8, 8,{0x00,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x00}}	// ON
};
	TCOLOR(pl);
	TEXTPUT((CX+x)*8,CY*16+y*8,&SemiG[mode]);
	TCOLOR(1); // 戻す
}

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

static WORD
f_ec66[] = {
	0x3333,0x3333,0xcccc,0xcccc,0x3333,0x3333,0xcccc,0xcccc,
	0x3333,0x3333,0xcccc,0xcccc,0x3333,0x3333,0xcccc,0xcccc
},
f_ec61[] = {
	0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,
	0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff
},
f_ec58[] = {
	0xffff,0x7fff,0x3fff,0x1fff,0x0fff,0x07ff,0x03ff,0x01ff,
	0x00ff,0x007f,0x003f,0x001f,0x000f,0x0007,0x0003,0x0001
},
f_ebf2[] = {
	0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
	0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff
},
f_ebf3[] = {
	0x8000,0xc000,0xe000,0xf000,0xf800,0xfc00,0xfe00,0xff00,
	0xff80,0xffc0,0xffe0,0xfff0,0xfff8,0xfffc,0xfffe,0xffff
},
f_ebf4[] = {
	0x0001,0x0003,0x0007,0x000f,0x001f,0x003f,0x007f,0x00ff,
	0x01ff,0x03ff,0x07ff,0x0fff,0x1fff,0x3fff,0x7fff,0xffff
},
f_ec59[] = {
	0xffff,0xfffe,0xfffc,0xfff8,0xfff0,0xffe0,0xffc0,0xff80,
	0xff00,0xfe00,0xfc00,0xf800,0xf000,0xe000,0xc000,0x8000
},
f_ec6d[] = {
	0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,
	0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff
},
f_ec6c[] = {
	0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,0x00ff,
	0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00
},
f_ec43[] = {
	0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,
	0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00,0xff00
},
f_ebfb[] = {
	0x0000,0x07e0,0x0810,0x1008,0x1008,0x2664,0x2664,0x2004,
	0x2004,0x23c4,0x1188,0x1008,0x0810,0x07e0,0x0000,0x0000
};

typedef struct { // 大フォント用構造体
	WORD	xl;
	WORD	yl;
	WORD	buffer[((T1X*16)/16)*T1Y*16];
} LRGFNT;

void MakeLargeFont(unchar *clist,LRGFNT *lfnt)
// コード群(clist)からT1X*T1Y分のフォントパターンを作る
// 特殊フォントのみを使うもののみ
{
WORD *f,*fnt,*font[T1X];
int i,j,k;
	// サイズ
	lfnt->xl=T1X*16;
	lfnt->yl=T1Y*16;
	f=lfnt->buffer;
	// フォント内容
	for (i=0;i<T1Y;i++) {
		// まず横T1X分のフォントを選ぶ
		for (j=0;j<T1X;j++) {
			// キャラクター→フォントパターン
			while (*clist=='/') clist++; // ｾﾊﾟﾚｰﾀｰを飛ばす
			switch (*clist++) {
				// それぞれは16*16dot char
				//  -> 2*16bytes
				case 0xef :fnt=f_ec66; break;
				case 0x3b :fnt=f_ec61; break;
				case 0x42 :fnt=f_ec58; break;
				case 0x43 :fnt=f_ebf2; break;
				case 0x4d :fnt=f_ebf3; break;
				case 0x4e :fnt=f_ebf4; break;
				case 0x56 :fnt=f_ec59; break;
				case 0x5b :fnt=f_ec6d; break;
				case 0x6c :fnt=f_ec6c; break;
				case 0x7b :fnt=f_ec43; break;
				case 0xcf :fnt=f_ebfb; break;
			}
			font[j]=fnt;
		}
		// 大フォントに再編成する
		for (k=0;k<16;k++) {
			for (j=0;j<T1X;j++) {
				fnt=font[j];
				*f++=fnt[k];
			}
		}
	}
}

// 大キャラクター T1X*T1Ychar -> (T1X*16)*(T1Y*16)dot
static LRGFNT chspc,chkabe,chkaeru,chdou,chkao1,chkao2;

void InitLargeFont()
// 大キャラクター定義
{
	chspc.xl=T1X*16;
	chspc.yl=T1Y*16;
	// chspc.fntは全0のままでよい
	MakeLargeFont("\xef\xef\xef/\xef\xef\xef/\xef\xef\xef",&chkabe);
	MakeLargeFont("\x4e\x43\x4d/\x7b\x43\x3b/\x6c\x43\x5b",&chkaeru);
	MakeLargeFont("\x4e\x43\x4d/\x43\x43\x43/\x42\x43\x56",&chdou);
	MakeLargeFont("\x4e\x43\x4d/\xcf\x43\xcf/\x42\x43\x56",&chkao1); // m=0 : 上下
	MakeLargeFont("\x4e\xcf\x4d/\x43\x43\x43/\x42\xcf\x56",&chkao2); // m=1 : 左右
}

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

void print_score(unchar *mes,int y,int sco)
{
	MZ_LOCATE(29,y);
	B_PRINT(mes);
	MZ_LOCATE(30,y+1);
	print_decII(sco,'0',5);
}

void score()
{
	print_score("ＳＣＯＲＥ",1,sco);
	B_PUTC('0');
}

void hi_score()
{
	print_score("ＨＩ−ＳＣＯＲＥ",4,hsc);
	B_PUTC('0');
}

void PrRound()
{
	print_score("ＲＯＵＮＤ",7,round);
}

void title()
// 得点など表示(L10000)
{
int i;
	cls();
	InitTvram();
	B_COLOR(TCYAN|HLIGHT|REVERSE);
	center(-2,"＊＊　レーダー・スネーキー ＰＲＯ６８Ｋ　＊＊");
	B_COLOR(TWHITE);
	// 画面枠
	for (i=CY-3;i<=CY+WY;i++) { // 縦
		B_LOCATE(CX-2   ,i); B_PUTC(L'□');
		B_LOCATE(CX+WX*2,i); B_PUTC(L'□');
	}
	for (i=CX-2;i<=CX+WX*2;i+=2) { // 横
		B_LOCATE(i,CY-3 ); B_PUTC(L'□');
		B_LOCATE(i,CY+WY); B_PUTC(L'□');
	}
	for (i=CX;i<=CX+WX*2-2;i+=2) { // 横
		B_LOCATE(i,CY-1); B_PUTC(L'−');
	}
	//
	for (i=0;i<=10;i++) {
		MZ_LOCATE(27,i);
		B_PRINT("｜　　　　　　　　　　　｜");
	}
		MZ_LOCATE(27,i);
		B_PRINT("＋−−−−−−−−−−−＋");
	score();
	hi_score();
	PrRound();
}

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

void RemakeLader()
// レーダーの再表示
{
int i;
	// 蛙の位置
	for (i=0;i<KMAX;i++) {
		if (td[i]==0) plot(ix[i],iy[i],1,KDPL);
	}
	// 蛇の位置は頭と尻尾以外表示できないのだ！
	plot(xx,yy,1,SDPL);
	plot(ox,oy,1,SDPL);
}

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

static struct FNTBUF
f_ec6e = {16,16
	,{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x10,0x00,0x28,0x00,0x44,0x00,0x82,0x02,
	0x01,0x04,0x00,0x88,0x00,0x50,0x00,0x20,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
},
f_ec6f = {16,16
	,{
	0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,
	0x00,0x20,0x00,0x40,0x00,0x80,0x01,0x00,
	0x02,0x00,0x04,0x00,0x08,0x00,0x04,0x00,
	0x02,0x00,0x01,0x00,0x00,0x80,0x00,0x40}
};

static unchar tvram[TWY][TWX];

void InitTvram()
/* 仮想テキストＶＲＡＭ初期化 */
{
int x,y;
	for (y=0;y<TWY;y++) {
		for (x=0;x<TWX;x++) tvram[y][x]=' ';
	}
}

void PrScreen(int mode)
// 仮想画面を画面上に表示する(L40000;大幅変更)
{
int i,k,m,col,c;
LRGFNT *lfnt;
int ii,kk=-1;
	if (!mode) tan++;
	// 一度に表示されるのは、adrをホームとしたTWX*TWYのブロックで、
	// 仮想画面上1キャラクターがT1X*T1Yのキャラクター(lfnt)で表示される
	m=(muki & 1);
	for (i=0;i<TWY;i++) { // Ｙ方向
		for (k=0;k<TWX;k++) { // Ｘ方向
		    c=SCWorkA[adr+i*FWX+k];
		    switch (c) {
			default: // スペース
				col=0x133; // TWHITE
				lfnt=&chspc;
				break;
			case KABE:
				col=0x133; // TWHITE;
				lfnt=&chkabe;
				break;
			case KAERU:
				col=0x111; // TCYAN;
				lfnt=&chkaeru;
				break;
			case DOU:
				col=0x122; // TYELLOW;
				lfnt=&chdou;
				break;
			case KAO:
				col=0x122; // TYELLOW;
				lfnt=(m==0? &chkao1:&chkao2);
				c+=m; // 顔の向きでキャラクターを変えるため
				kk=k; // 顔の位置記録
				ii=i;
				break;
		    } // switch
		    // キャラクターの表示
		    if (tvram[i][k]!=c) { // 前と変わるところだけ
			tvram[i][k]=c;
			B_WPOKE((unshort *)0xe8002a,col); // 同時アクセスon
			TEXTPUT(CX*8+k*T1X*16,(CY+i*T1Y)*16,lfnt);
			if (col!=0x133) { // 白以外
				// 排他プレーンクリア
		    		B_WPOKE((unshort *)0xe8002a,col^0x33);
				TEXTPUT(CX*8+k*T1X*16,(CY+i*T1Y)*16,&chspc);
		    	}
		    } // 前と同じ
		} // k
	} // i
	B_WPOKE((unshort *)0xe8002a,0x033); // 同時アクセスoff
	if ((tan&2)==0) { // 舌
	  int x0,y0;
	    if (kk!=-1) { // 通常頭は表示されるが、GameOver時だけはそうでないことがある
		x0=kk*T1X;
		y0=ii*T1Y;
		switch (muki) {
			case 0:x0++;  y0--;  ii--; break; // 上
			case 1:x0--;  y0++;  kk--; break; // 左
			case 2:x0++;  y0+=3; ii++; break; // 下
			case 3:x0+=3; y0++;  kk++; break; // 右
		}
		tvram[ii][kk]=0xff; // 次回画面が更新されるようにする
		MZ_LOCATE(x0,y0);
		B_COLOR(TYELLOW);
		FONTPUT2(m==0? &f_ec6f:&f_ec6e);
		B_COLOR(TWHITE);
	    }
	}
	switch (oto) {
	    case 1: // 蛙を食べる音
		PCMplay(PCMhiq,LENhiq,-1);
		break;
	    case 2: // 頭を入れ換える音
		PCMplay(PCMrhiq,LENrhiq,-2);
		break;
	}
	oto=0;
	plot(xx,yy, 1,SDPL);
	plot(ox,oy,mo,SDPL);
	ox=sx;
	oy=sy;
	for (i=0;i<KMAX;i++) {
		if (td[i]==0) {
			plot(rx[i],ry[i],0,KDPL);
			plot(ix[i],iy[i],1,KDPL);
			rx[i]=ix[i];
			ry[i]=iy[i];
		}
	}
	WaitPCM();
}

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

int getky()
/* キー入力：複数キーの設定を可能にするため */
/* でも基本操作はテンキーで行う */
/* 一応JOYSTICK対応だよ */
{
int c,js;
	c=inkey2(1,0);
	if (c==0) { /* not key enter */
		/* JOY STICK input */
		js=JOYGET(0)&JOYGET(1);
		if ((js&BIT6)==0) c='5';
		if ((js&BIT5)==0) c='5';
		if ((js&BIT3)==0) c='6';
		if ((js&BIT2)==0) c='4';
		if ((js&BIT1)==0) c='2';
		if ((js&BIT0)==0) c='8';
	}
	
	switch (c) { /* カーソルキー対応コード変換 */
		case SKleft: /* left */
			c='4';
			break;
		case SKup: /* up */
			c='8';
			break;
		case SKright: /* right */
			c='6';
			break;
		case SKdown: /* down */
			c='2';
			break;
	}
	
	c&=0xff;
	switch (c) {
		/* 向き変更 */
		case ' ':c='5'; break;
		/* その他 */
		case 0x0d:/* PANIC */
			curon();
			cls();
			spawnlp(P_WAIT,exec,exec,NULL,NULL);
			CRTMOD(16); // cwidth(96);
			title(); /* タイトル表示 */
			RemakeLader(); // レーダー再表示
			PrScreen(1); // 再表示
		case ESC:/* PAUSE */
			curon();
			center(WY+2,"ＰＡＵＳＥ");
			if (KFLUSHGC()=='!') { // キー入力待ち
		    case '!':/* BREAK */
				curon();
				exit(1);
				/* なんとサブルーチンからexit()しているのだ。 */
				/* あまりお勧めは出来ない技だからみなさんはまねしないでね！ */
			}
			center(WY+2,"　　　　　");
			curoff();
			break;
	}
	return(c);
}

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

int TurnHead()
// 頭の入れ替え（L1600）
{
int i,a,b;
	a=adr+136;
	b=0;
	for (i=0;i<4;i++) { // 上左下右
		if (SCWorkA[a+v[i]]==DOU) b++;
	}
	if (b!=1) return(1); // 自分の体で行き詰まり=終わり
	SCWorkA[a   ]=DOU;
	SCWorkA[sipo]=KAO;
	tan=1;
	oto=2; // 向きを変えるの音
	adr=sipo-136;
	sipo=a;
	// 頭と尻尾座標入れ替え(dot)
	a=xx; xx=sx; sx=a; ox=a;
	a=yy; yy=sy; sy=a; oy=a;
	return(0);
}

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

void MoveSipo()
// 尻尾移動（L7000）
{
int i;
	for (i=0;i<=2;i++) { // まわりを調べる
		if (SCWorkA[sipo+v[i]]==DOU) break;
	}
	switch (i) {
		case 0:sy--; break; // 上
		case 1:sx--; break; // 左
		case 2:sy++; break; // 下
		case 3:sx++; break; // 右
	}
	SCWorkA[sipo]=' ';
	sipo+=v[i];
	mo=0; // 尻尾非表示
}

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

void EatKaeru(int i)
// 蛙食べた(L9000)
{
	sco+=round;
	score();
	oto=1; // 蛙食べたの音
	td[i]=1;
//	ici[i]=-1;
	eat--;
	plot(ix[i],iy[i],0,KDPL);
}

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

void MoveSnake()
// 蛇の移動（L1000）
{
int t,g,p,i;
	if (die||!eat) return;
	mo=1; // 尻尾表示
	switch (getky()) {
		case '8':p=0; break;
		case '4':p=1; break;
		case '2':p=2; break;
		case '6':p=3; break;
		case '5':
			die=TurnHead();
		default:
			return;
	}
	t=g=0;
	while (1) { // 移動先は何？
	    switch (SCWorkA[adr+136+v[p]]) {
		case DOU:
			if (SCWorkA[adr+136-v[p]]==DOU) die=1;
			if (die) break;
		case KABE:
			// L1500
			if (t) return;
			t=1;
			p=muki; // 向きの自動変換
			continue;
		case KAERU: // L5000
			for (i=0;i<KMAX;i++) {
			    if (td[i]==0) {
				// 蛙が重なっていることもあるので、全部チェックする
				if (ici[i]==adr+136+v[p]) EatKaeru(i);
			    }
			}
			g=1;
			break;
	    }
	    break;
	}
	muki=p;
	SCWorkA[adr+136]=DOU;
	adr+=v[p];
	SCWorkA[adr+136]=KAO;
	if (g==0) { // スペースへ移動
		if (non!=0) {
			non--; // 胴体長さ＋１
		} else {
			MoveSipo(); // 長さ不変
		}
	} // 蛙へ移動 : 長さ＋１（一度に２匹以上食べた時も増える長さは＋１）
	// 尻尾移動する  ＝長さ不変
	// 尻尾移動しない＝長さ＋１
	// 結局、動くのは頭と尻尾だけで、胴体部分は残像である。
	switch (muki) {
		case 0:yy--; break; // 上
		case 1:xx--; break; // 左
		case 2:yy++; break; // 下
		case 3:xx++; break; // 右
	}
}

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

void InitHEBI()
// スネーク初期化（L20080）
{
	muki=tan=0; // 向き＝上、舌＝消えている
	SCWorkA[0x310]=KAO;
	SCWorkA[0x331]=DOU;
	sipo=0x352;
	SCWorkA[sipo] =DOU;
	   xx=76;    yy=43; plot(xx,yy,1,SDPL); // 頭
		            plot(76,44,1,SDPL); // 胴体
	ox=sx=76; oy=sy=45; plot(sx,sy,1,SDPL); // 尻尾
}

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

void KaeruMove()
// 蛙移動＆方向転換(L60000)
{
int i,w,pp,yo;
	for (i=0;i<KMAX && !die;i++) {
		if (td[i]!=0) continue;
		// 自分の移動方向に対して垂直移動ができる時は向きを変える
		// 行き先が蛇で有っても・・・
		pp=der[i]&1; // 上=0,左=1,下=2,右=3 -> 0,1,0,1
		if (SCWorkA[ici[i]+v[1-pp]]!=KABE
		 || SCWorkA[ici[i]+v[3-pp]]!=KABE) {
			// 方向変換(L62000)
			do {
				w=rand2(4);
				// 前と正反対の方向か壁方向には向かない
			} while ((der[i]^2)==w || SCWorkA[ici[i]+v[w]]==KABE);
			der[i]=w;
		}
		pp=der[i];
		yo=SCWorkA[ici[i]+v[pp]];
		if (yo==DOU) die=1;
		SCWorkA[ici[i]]=' ';
		if (yo==KAO) { // 蛇の頭に自分から入っていく
			EatKaeru(i);
			non++; // 蛇の長さ＋１
			continue;
		}
		ici[i]+=v[pp];
		SCWorkA[ici[i]]=KAERU;
		switch (der[i]) {
			case 0:iy[i]--; break; // 上
			case 1:ix[i]--; break; // 左
			case 2:iy[i]++; break; // 下
			case 3:ix[i]++; break; // 右
		}
		if (die) {
			// 次でゲームオーバーになるので、画面を食いついた場所に移す
			PCMplay(PCMpack,LENpack,2);
			adr=ici[i]-136;
		}
	}
}

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

void SetKAERU()
// 蛙配置（L50000）
{
int i,tx,ty,qq;
	for (i=0;i<KMAX;i++) {
		do { // 交差点に配置する
			tx=(rand2(9))*3;
			ty=(rand2(8))*3;
			qq=ty*FWX+tx+FHOME;
		} while (SCWorkA[qq]!=' ');
		ici[i]=qq;
		SCWorkA[qq]=KAERU;
		// dot MAP座標
		rx[i]=ix[i]=(tx+55);
		ry[i]=iy[i]=(ty+24);
		plot(ix[i],iy[i],1,KDPL);
		PCMplay(PCMhiq,LENhiq,-4);
		der[i]=rand2(4); // 3; 初期移動方向
		td[i]=0;
		WaitPCM();
	}
	eat=i; // KMAX
	non=0;
}

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

void SetSCWorkA()
// 仮想画面にフィールドをセットする(L30000)
{
int x,y;
	// 一旦全て埋める
	for (x=0;x<FWX*FWY;x++) SCWorkA[x]=KABE;
	// 横に道を作る
	for (y=FHY;y<=FEY;y+=3) {
		for (x=FHX;x<=FEX;x++) SCWorkA[y*FWX+x]=' ';
	}
	// 縦に道を作る
	for (x=FHX;x<=FEX;x+=3) {
		for (y=FHY;y<=FEY;y++) SCWorkA[x+y*FWX]=' ';
	}
}

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

int GameOver()
// ret=1:retry,0=end
// L2000
{
int i,ky;
	B_COLOR(TCYAN|HLIGHT);
	for (i=1;i<=6;i++) {
		MZ_LOCATE(11,11); B_PRINT("＼   ｜   ／");
		MZ_LOCATE(11,12); B_PRINT("＿ＧＡＭＥ　");
		MZ_LOCATE(11,13); B_PRINT("　ＯＶＥＲ￣");
		MZ_LOCATE(11,14); B_PRINT("／   ｜   ＼");
		beep();
		vwait(16);
		if (i==5) break;
		MZ_LOCATE(11,11); B_PRINT(" ＼  ｜  ／ ");
		MZ_LOCATE(11,12); B_PRINT("  ☆☆☆☆＿");
		MZ_LOCATE(11,13); B_PRINT("￣☆☆☆☆  ");
		MZ_LOCATE(11,14); B_PRINT(" ／  ｜  ＼ ");
//		MZ_LOCATE(11,11); B_PRINT("            ");
//		MZ_LOCATE(11,12); B_PRINT("            ");
//		MZ_LOCATE(11,13); B_PRINT("            ");
//		MZ_LOCATE(11,14); B_PRINT("            ");
		vwait(20);
	}
	B_COLOR(TWHITE);
	if (sco>hsc) {
		PCMplay(PCMappl,LENappl,-4);
		B_COLOR(TCYAN|REVERSE|HLIGHT);
		center(8,"＊＊　新記録！！　＊＊");
		B_COLOR(TWHITE);
		hsc=sco;
		hi_score();
	}
	center(10,"もう一度しますか？");
	curon();
	do {
		ky=KFLUSHGC(); // toupperマクロ化対応
		ky=toupper(ky);
	} while (ky!='Y' && ky!='N' && ky!=0x1b);
	a_end(); // 音を止める
	return(ky=='Y');
}

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

int move1(int mode)
// 蛇・蛙移動＆画面表示などなど
{
	MoveSnake();
	if (mode) KaeruMove();
	PrScreen(0);
	if (die) return(1);
	if (eat==0) { // L3000
	    int i;
		round++; PrRound(); // 面を進める
		for (i=1;i<=2;i++) { // 胴体を２縮める
			plot(sx,sy,0,SDPL);
			PCMplay(PCMhiq,LENhiq,-2);
			MoveSipo(); // 移動方向に進める＝縮める
			WaitPCM();
			vwait(11);
		}
		return(2);
	}
	vwait(10);
	return(0);
}

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

void main(int argc,unchar *argv[])
{
int ret;
FILE *fp;
	hsc=0; /* ハイスコアクリア */
	fp=fopen(RECHIGH,"rb");
	if (fp!=NULL) { /* hi-score read */
		fread(&hsc,sizeof(hsc),1,fp);
		fclose(fp);
	}
	
	/* 乱数初期化 */
	srand2();
	
	/* PANIC起動プログラム名 */
	exec=getenv2("PANIC","COMMAND.X");
	
	/* ADPCM読み込み */
	LENappl=fmalloc(&PCMappl,"APL.PCM" ,0,0);
	LENhiq =fmalloc(&PCMhiq ,"HIQ.PCM" ,0,0);
	LENrhiq=fmalloc(&PCMrhiq,"RHIQ.PCM",0,0);
	LENpack=fmalloc(&PCMpack,"SCRCH4.PCM",0,0);
	
	// 画面関係
	CRTMOD(16); // cwidth(96);
	help_set(argv[0],0);
	InitLargeFont(); // 大キャラクター作成
	
	// 方向別アドレス増分
	do {
		curoff();
		// その他変数
		adr=0x288; // SCWorkA内
		round=1;
		sco=0;
		oto=0;
		die=0;
		mo=1; // 尻尾表示
		//
		title();
		SetSCWorkA();
		InitHEBI();
		do {
			SetKAERU();	// 初期蛙表示
			PrScreen(0);	// 画面表示
			do {
				ret=move1(0); // 蛇のみ移動
				if (ret) break;
				ret=move1(1); // 蛙も移動
			} while (!ret);
		} while (ret==2);
	} while (GameOver());
	//
	fp=fopen(RECHIGH,"wb");
	if (fp!=NULL) { /* hi-score write */
		fwrite(&hsc,sizeof(hsc),1,fp);
		fclose(fp);
	}
	/* ADPCMバッファー開放 */
	if (PCMappl!=NULL) free(PCMappl);
	if (PCMhiq !=NULL) free(PCMhiq );
	if (PCMrhiq!=NULL) free(PCMrhiq);
	if (PCMpack!=NULL) free(PCMpack);
	exit(0);
}

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