/******************************************************************/
//	ルナ・レスキュー−ＰＲＯ６８Ｋ
//		Ｉ／Ｏ合本 ＭＺ−８０活用研究 よりの移植
//  Ａｒｒａｎｅｄ  １９９７  ｂｙ  ＡＩＧ−ＳＯＦＴ
/******************************************************************/

#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[]="@@> LUNAR.C : 1998/01/16 FRI : GAME : LUNAR RESCUE";

// 97/10/12 : 初版
// 97/10/17-18 : ドッキング失敗時の人の落下のバグを修正、細部調整
// 97/11/09 : 画面モード強制変更(ファイラーからの直接起動対応)
//            キーバッファーをクリアして誤動作を減らす
// 98/01/16 : PAUSE中も'!'でexit出来るようにする
/******************************************************************/

#define	LSAN	'<'	/* ebf4 : 左△ */
#define	RSAN	'>'	/* ebf3 : 右△ */
#define	UFO	'ﾕ'	/* eb69 : UFO */
#define	SHIP	'='	/* ec5a : 宇宙船 */
#define	BASE1	'%'	/* ec66 : 着地点 高得点 */
#define	BASE2	'&'	/* ebf2 : 着地点 低得点 */

#define	GATE	'~'	/* ec78 : 母船開いているゲート */
#define	MADO	'M'	/* ec6b : 母船窓 */
#define	MAN	'ﾏ'	/* ebeb : 人 */
#define	DMAN	'ﾙ'	/* ebee : 落ちる人 */
#define	MISS	'!'	/* ec6f : UFOミサイル */
#define	LSHIP	'['	/* ec65 : 母船足左側 */
#define	RSHIP	']'	/* ec64 : 母船足右側 */
#define	DAN1	'z'	/* ec77 : 地面１ */
#define	DAN2	'Z'	/* ec76 : 地面２ */
#define	DAN3	'x'	/* ec75 : 地面３ */
#define	DAN4	'X'	/* ebf0 : 地面４ */
#define	LOPEN	'L'	/* ec71 : 母船開き左 */
#define	ROPEN	'R'	/* ec70 : 母船開き右 */

#define	STONE	'o'	/* 隕石 */
#define	FIRE	'V'	/* ロケット：火 */
#define	BEAM	'ﾋ'	/* 宇宙船のビーム */

/* タイトル画面のみ */
#define	HOSHI	'.'	/* 星 */
#define	LBAR	'^'	/* ＼ : ロボット頭 */
#define	RBAR	'/'	/* ／ : ロボット頭 */
#define	EYE	'@'	/* ● : ロボット目 */
#define	LSIDE	'{'	/* ec61 : ロボット顔左 */
#define	RSIDE	'}'	/* ec43 : ロボット顔右 */
#define	LASHI	':'	/* ec73 : ロボット足左 */
#define	RASHI	';'	/* ec72 : ロボット足右 */
#define	TASHI	'+'	/* ┳ : ロボット足付け根 */
#define	LUBLK	'7'	/* ┏ */
#define	RUBLK	'9'	/* ┓ */
#define	LLBLK	'1'	/* ┗ */
#define	RLBLK	'3'	/* ┛ */
#define	VBAR	'|'	/* ┃ */
#define	HBAR	'-'	/* ━ */

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

#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	KLEFT	'4'
#define	KUP	'5'
#define	KRIGHT	'6'
#define	KLDOWN	'1'
#define	KDOWN	'2'
#define	KRDOWN	'3'

#define	H2INIT	3		/* 左側の人の初期の数（変更不可）*/
#define	H3INIT	3		/* 右側の人の初期の数（変更不可）*/
#define	H4INIT	3		/* 宇宙船の初期の数 */

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

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

int	sco,hsc;	/* 得点 */
int 	men;		// 面数
int	h2;		// 左側の人の数
int	h3;		// 右側の人の数
int	h4,h4up;	// 宇宙船の数,宇宙船が増えたかどうか
unchar	cfuyu;		// 空中に浮かんでいるもの（隕石／ＵＦＯ）
int	x1,y1,h1;	// 母船の座標、移動方向(h1=1:右,0=左)
int	x2,y2;		// 宇宙船の座標
int	x3,y3;		// ビーム座標
int	cl;		// 動作タイミングカウンタ

unchar	*jimen[]={	// 地面パターン
	 " zZx%%%xZz zZxZz<&&&&&>zZz "
	,"<> zZxxZZz<%%>Zz   zZ<&&&&z"
	,"zZZxxX&&&&XxxZZz  zZz <%%> "
	," zZxxxXX%%XxXxZzz zZxX&&&>z"
	,"<&&>zzzzZZZZz zZxxxZz <%Xxz"
};

#define	MENMAX	(sizeof(jimen)/sizeof(unchar*))	/* 面の繰り返し:1〜MENMAX-1 */
#define	BOSENY		1			/* 母船の動くＹ座標（ここから３）*/
#define	FUYUY		6			/* 浮遊物の動くＹ座標（ここから）*/
#define	FUYUMIN		9			/* 一番最初の面での浮遊物の有る行数 */
#define	FUYUWY		(FUYUMIN+MENMAX+1)	/* 浮遊物のＹ幅 */

struct	{
	int	x;	// x座標
	int	direc;	// 移動方向(0=右,1=左)
} fuyu[FUYUWY];

// ADPCM用変数
unchar	*PCMbang,*PCMopen,*PCMdock,*PCMdown,*PCMpong,*PCMchak,*PCMman,*PCMappl,*PCMhiq;
int	LENbang,LENopen,LENdock,LENdown,LENpong,LENchak,LENman,LENappl,LENhiq;

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

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

int LeftDisp(int y,unchar *mes,unchar ch)
// 文字列が本来センタリングで表示される場所に左から１文字づつ表示する
// ２文字単位専用
{
unchar s[WX];
int i,x,len;
	len=strlen(mes);
	x=(GWX-len)/2;
	for (i=2;i<=len;i+=2) {
		memcpy(s,mes,i);
		s[i]=0;
		B_LOCATE(x,y+CY);
		B_PRINT(s);
		if (getky()==ch) return(1);
		vwait(14);
	}
	return(0);
}

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

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);
	}
}

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

struct FNTBUF
f_ebf3 = {16,16
	,{
	0x80,0x00,0xc0,0x00,0xe0,0x00,0xf0,0x00,
	0xf8,0x00,0xfc,0x00,0xfe,0x00,0xff,0x00,
	0xff,0x80,0xff,0xc0,0xff,0xe0,0xff,0xf0,
	0xff,0xf8,0xff,0xfc,0xff,0xfe,0xff,0xff}
},
f_ebf4 = {16,16
	,{
	0x00,0x01,0x00,0x03,0x00,0x07,0x00,0x0f,
	0x00,0x1f,0x00,0x3f,0x00,0x7f,0x00,0xff,
	0x01,0xff,0x03,0xff,0x07,0xff,0x0f,0xff,
	0x1f,0xff,0x3f,0xff,0x7f,0xff,0xff,0xff}
},
f_ec69 = {16,16
	,{
	0x00,0x00,0x01,0x80,0x07,0xe0,0x1f,0xf8,
	0x3f,0xfc,0x32,0x4c,0x32,0x4c,0xff,0xff,
	0xff,0xff,0x7f,0xfe,0x3f,0xfc,0x1f,0xf8,
	0x1e,0x78,0x0c,0x30,0x00,0x00,0x00,0x00}
},
f_ec5a = {16,16
	,{
	0x00,0x00,0x18,0x18,0x18,0x18,0x1f,0xf8,
	0x19,0x98,0x01,0x80,0x01,0x80,0x01,0x80,
	0x01,0x80,0x01,0x80,0x61,0x86,0x61,0x86,
	0x7f,0xfe,0x7f,0xfe,0x60,0x06,0x00,0x00}
},
f_ec66 = {16,16
	,{
	0x33,0x33,0x33,0x33,0xcc,0xcc,0xcc,0xcc,
	0x33,0x33,0x33,0x33,0xcc,0xcc,0xcc,0xcc,
	0x33,0x33,0x33,0x33,0xcc,0xcc,0xcc,0xcc,
	0x33,0x33,0x33,0x33,0xcc,0xcc,0xcc,0xcc}
},
f_ebf2 = {16,16
	,{
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
},
f_ec78 = {16,16
	,{
	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
},
f_ec6b = {16,16
	,{
	0xff,0xff,0xf8,0x1f,0xe0,0x07,0xc0,0x03,
	0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,
	0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,
	0xc0,0x03,0xe0,0x07,0xf8,0x1f,0xff,0xff}
},
f_ebeb = {16,16
	,{
	0x00,0x00,0x07,0xe0,0x07,0xe0,0x07,0xe0,
	0x07,0xe0,0x01,0x80,0x01,0x80,0x3f,0xfc,
	0x01,0x80,0x01,0x80,0x03,0xc0,0x06,0x60,
	0x0c,0x30,0x18,0x18,0x30,0x0c,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}
},
f_ec65 = {16,16
	,{
	0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
	0x01,0x80,0x01,0xc0,0x00,0xe0,0x00,0x7f,
	0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
},
f_ec64 = {16,16
	,{
	0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
	0x01,0x80,0x03,0x00,0x07,0x00,0xfe,0x00,
	0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
},
f_ec77 = {16,16
	,{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff}
},
f_ec76 = {16,16
	,{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
},
f_ec75 = {16,16
	,{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
},
f_ebf0 = {16,16
	,{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
},
f_ec61 = {16,16
	,{
	0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,
	0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,
	0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,
	0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff}
},
f_ec43 = {16,16
	,{
	0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
	0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
	0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
	0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00}
},
f_ec73 = {16,16
	,{
	0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,
	0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,
	0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,
	0x00,0x03,0x00,0x03,0xff,0xff,0xff,0xff}
},
f_ec72 = {16,16
	,{
	0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,
	0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,
	0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,
	0xc0,0x00,0xc0,0x00,0xff,0xff,0xff,0xff}
},
f_ec70 = {16,16
	,{
	0xff,0xff,0xff,0xff,0xc0,0x00,0xc0,0x00,
	0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,
	0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00,
	0xc0,0x00,0xc0,0x00,0xc0,0x00,0xc0,0x00}
},
f_ec71 = {16,16
	,{
	0xff,0xff,0xff,0xff,0x00,0x03,0x00,0x03,
	0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,
	0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,
	0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03}
},
f_ebee = {16,16
	,{
	0x00,0x00,0x30,0x0c,0x18,0x18,0x0c,0x30,
	0x06,0x60,0x03,0xc0,0x01,0x80,0x01,0x80,
	0x3f,0xfc,0x01,0x80,0x01,0x80,0x07,0xe0,
	0x07,0xe0,0x07,0xe0,0x07,0xe0,0x00,0x00}
};

static unchar tvram[WY][WX];

void printxy(int x,int y,unchar c)
/* 仮想画面と実画面変換を行う */
/* 内部処理キャラクターと表示キャラクターの変換を行う */
/* 仮想画面はWX桁、WY行で(0,0)〜(WX-1,WY-1)を表す */
{
_FNTBUF *font,font0;
int cc=0;
	/* 仮想テキストＶＲＡＭに出力 */
	tvram[y][x]=c;
	
	/* 座標変換 */
	/* 最下行は使えない */
	B_LOCATE(CX+x*2,CY+y);
	
	/* キャラクター変換 */
	switch (c) {
		// 半角全角変換
		default   :cc=hantozen(c); break;
		
		// 特殊変換
		case LBAR :cc=L'＼'; break;
		case RBAR :cc=L'／'; break;
		case EYE  :cc=L'●'; break;
		case TASHI:cc=L'┳'; break;
		case LUBLK:cc=L'┏'; break;
		case RUBLK:cc=L'┓'; break;
		case LLBLK:cc=L'┗'; break;
		case RLBLK:cc=L'┛'; break;
		case VBAR :cc=L'┃'; break;
		case HBAR :cc=L'━'; break;
		case BEAM :cc=L'｜'; break;
		
		/* 外字変換 */
		case LSAN :font=&f_ebf4; break;
		case RSAN :font=&f_ebf3; break;
		case UFO  :font=&f_ec69; break;
		case SHIP :font=&f_ec5a; break;
		case BASE1:font=&f_ec66; break;
		case BASE2:font=&f_ebf2; break;
		case GATE :font=&f_ec78; break;
		case MADO :font=&f_ec6b; break;
		case MAN  :font=&f_ebeb; break;
		case DMAN :font=&f_ebee; break;
		case LSHIP:font=&f_ec65; break;
		case RSHIP:font=&f_ec64; break;
		case DAN1 :font=&f_ec77; break;
		case DAN2 :font=&f_ec76; break;
		case DAN3 :font=&f_ec75; break;
		case DAN4 :font=&f_ebf0; break;
		case LSIDE:font=&f_ec61; break;
		case RSIDE:font=&f_ec43; break;
		case LASHI:font=&f_ec73; break;
		case RASHI:font=&f_ec72; break;
		case LOPEN:font=&f_ec71; break;
		case ROPEN:font=&f_ec70; break;
		case MISS :font=&f_ec6f; break;
	}
	if (cc!=0) {
		// 普通文字
		B_PUTC(cc);
	} else {
		if (B_COLOR(-1)!=TWHITE) {
			// フォントが加工される時はバッファーにコピーしてから行う
			font0=*font; // 構造体のコピー
			font=&font0;
		}
		// 外字
		fontset(font);
		FONTPUT2(font);
	}
}

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

void RScroll(int ys,int ye)
// 特定行領域右ローテート
{
int y,x;
unchar c;
	for (y=ys;y<=ye;y++) {
		c=tvram[y][WX-1];
		for (x=WX-1-1;x>=0;x--) printxy(x+1,y,tvram[y][x]);
		printxy(0,y,c);
	}
}

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

void printxys(int x,int y,unchar *s)
// 文字列表示
{
int i;
	for(i=0;i<strlen(s);i++) {
		printxy(x,y,s[i]);
		x++;
		if (x>=WX) {x=0; y++;}
		if (y>=WY) y=WY-1;
	}
}

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

int scrn(int x,int y)
/* 仮想テキストＶＲＡＭを読み出す */
{
	return(tvram[y][x]);
}

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

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

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

void pop_tvram()
/* 仮想テキストＶＲＡＭ表示 */
{
int x,y;
	for (y=0;y<WY;y++) {
		for (x=0;x<WX;x++) printxy(x,y,tvram[y][x]);
	}
}

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

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(); // 音が止まるまで待つ
	}
}

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

void print_score(int sco)
{
	if (sco<0) {B_PUTC('-'); sco=-sco;} // マイナス得点
	print_decII(sco,'0',5);
	B_PUTC(' '); // - → +になった時の後ろ消しのため
}

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

void hi_score()
/* ハイスコア表示 */
{
	B_LOCATE(CX+1,CY); B_PRINT("HI-SCORE:");
	print_score(hsc);
}

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

void score(int point)
/* 得点加算＆表示 */
{
	sco+=point;
	B_LOCATE(CX+19,CY); B_PRINT("SCORE:");
	print_score(sco);
}

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

void title()
/* タイトル表示 */
{
	B_COLOR(TCYAN|HLIGHT|REVERSE);
	center(-2,"＊＊　ルナ・レスキュー ＰＲＯ６８Ｋ　＊＊");
	B_COLOR(TWHITE);
	score(0);
	hi_score();
}

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

void ACLS()
{
	init_tvram();	/* 仮想テキストＶＲＡＭクリア */
	cls();
}

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

void PrMAN()
// 人の表示
{
	// 左側の人の表示
	printxy( 0,20,' '); printxy( 2,21,' '); printxy( 4,22,' ');
	if (h2==3) printxy( 0,20,MAN);
	if (h2>=2) printxy( 2,21,MAN);
	if (h2>=1) printxy( 4,22,MAN);
	// 右側の人の表示
	printxy(35,22,' '); printxy(37,21,' '); printxy(39,20,' ');
	if (h3==3) printxy(35,22,MAN);
	if (h3>=2) printxy(37,21,MAN);
	if (h3>=1) printxy(39,20,MAN);
}

void PrScreen()
{
int i;
	title();
	if (sco>=1500 && !h4up) {
		h4up=1;
		h4++;
	}
	// 宇宙船の数表示
	B_LOCATE(CX+34*2-5,CY); B_PRINT("LEFT:");
	for (i=0;i<h4-1;i++) printxy(34+i,0,SHIP);
	printxy(34+i,0,' '); // 後ろを消す
	// 人の表示
	PrMAN();
}

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

void init1()
// １機毎の初期化
{
int i;
	ACLS();		// 画面クリア
	// 画面枠
	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'−');
	}
	
	cfuyu=STONE;	// 隕石が浮かんでいる
	x3=-1;		// 宇宙船のビームは未表示
	x1=4; y1=1; 	// 母船の位置
	h1=1; 		// 母船の向き
	cl=0;
	
	// 浮遊物の初期x座標と移動方向
	for (i=0;i<9+men;i++) {
		fuyu[i].x    =rand2(WX-3)+1;
		fuyu[i].direc=rand2(2);
	}
	for (;i<FUYUWY;i++) fuyu[i].x=-1; // 未使用の印
	
	for (i=0;i<WX;i++) printxy(i,24,GATE);
	printxys( 0,21,"&>"   );
	printxys( 0,22,"&&&>"  );
	printxys( 0,23,"&&&&&>");
	printxys(38,21,    "<&");
	printxys(36,22,  "<&&&");
	printxys(34,23,"<&&&&&");
	printxys( 7,23,jimen[men-1]);
	
	PrScreen();
}

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

int disp()
/* 画面初期化 */
{
int i,x,y;
time_t ts,t;
	do {
		ACLS();
		
		// 画面に星を撒く
		for (i=1;i<=99;i++) {
			x=rand2(WX);
			y=rand2(WY);
			printxy(x,y,HOSHI);
		}
		
		// タイトル表示
		title();
		
		// スタートボタン待ち
		center(4,"Ｐ Ｌ Ａ Ｙ");
		vwait(14);
		if (LeftDisp(6,"ＬＵＮＡＲ　ＲＥＳＣＵＥ",'S')) return('S');
		vwait(14);
		if (LeftDisp(8,"ＰＵＳＨ　ＯＮＬＹ 'Ｓ' ＢＵＴＴＯＮ",'S')) return('S');
		vwait(14);
		x=WX/2-2;
		printxys(x,15,"^<>/");
		printxys(x,16,"{@@}");
		printxys(x,17,"[++] 7-9");
		printxys(x,18,"(%%~ |S|");
		printxys(x,19," :;  1-3");
		center(13,"ＳＴＡＲＴ！");
		PCMplay(PCMappl,LENappl,-4);
		
		time(&ts);
		do {
			x=getky();
			if (x=='S') break;
			time(&t);
		} while (t-ts<20); /* 20秒たったら自動的に再表示する */
		a_end(); // ADPCMを止める
	} while (x!='S');
	return(x);
}

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

void PrShips(unchar c)
// 宇宙船等のまわりにパターンを描く
{
	printxy(x2-1,y2-1,c);
	printxy(x2  ,y2-1,c);
	printxy(x2+1,y2-1,c);
	printxy(x2-1,y2  ,c);
	printxy(x2  ,y2  ,c);
	printxy(x2+1,y2  ,c);
	printxy(x2-1,y2+1,c);
	printxy(x2  ,y2+1,c);
	printxy(x2+1,y2+1,c);
	while (kbhit()) getch(); // キーバッファークリア
}

int BreakShip()
// 宇宙船爆発
{
	B_COLOR(TYELLOW|HLIGHT);
	PrShips('*');
	B_COLOR(TWHITE);
	PCMplay(PCMbang,LENbang,4);
	PrShips(' ');
	return(--h4>0);
}

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

void MoveFuyu()
// 浮遊物移動
{
int i,x;
	for (i=0;i<FUYUWY;i++) {
		if (fuyu[i].x<0) continue;
		x=fuyu[i].x;
		printxy(x,FUYUY+i,' ');
		if (fuyu[i].direc==0) { // 右移動
			x++;
			if (x==39) fuyu[i].direc=1; // 方向転換
		} else { // 左移動
			x--;
			if (x==0) fuyu[i].direc=0; // 方向転換
		}
		fuyu[i].x=x;
		printxy(x,FUYUY+i,cfuyu);
	}
}

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

void MoveBosen()
// 母船移動
// y=1,2,3を右に移動
{
	RScroll(1,3);
}

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

void MoveMissile()
// UFOのミサイルを下げる
{
int y,x,c;
#define	EX	(WY-1-3)
	for (y=FUYUY;y<EX;y++) {
	    for (x=0;x<WX;x++) {
		c=scrn(x,y);
		if (c==MISS) {
			printxy(x,y,' ');
			y++;
			// 画面内でかつ下がスペースの時のみ下げる
			if (y>=EX) continue;
			if (scrn(x,y)==' ') {
				B_COLOR(TCYAN|HLIGHT);
				printxy(x,y,MISS);
				B_COLOR(TWHITE);
			}
		}
	    }
	}
}

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

void BeamUp()
// ビーム上昇
{
int c;
	if (x3<0) return;
	
	printxy(x3,y3--,' '); // 前の場所を消す
	c=scrn(x3,y3); // 上げる先の場所
	if (c==UFO) {
		printxy(x3,y3,'*');
		PCMplay(PCMpong,LENpong,-4);
		fuyu[y3-FUYUY].x=-1; // この浮遊物はなくなった
		score(50);
		WaitPCM();
		printxy(x3,y3,' ');
		x3=-1;
		return;
	}
	if (c==MISS) {
		// ビームを消す
		PCMplay(PCMhiq,LENhiq,-4);
		printxy(x3,y3,' ');
		x3=-1;
		return;
	}
	if (c!=' '||y3<FUYUY) {
		x3=-1;
		return;
	}
	B_COLOR(TYELLOW|HLIGHT);
	printxy(x3,y3,BEAM);
	B_COLOR(TWHITE);
}

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

int GameMain()
// return : 1=まだ続ける , 0=終わり
{
int ch,i;
	//母船の移動（出発待ち;L100）
	while (1) {
		/* キー入力 */
		ch=getky();
		// 母船表示		x1
		//		        |
		printxys(x1-2,y1  ,  " <X> ");
		printxys(x1-4,y1+1," <MM=MM> ");
		printxys(x1-4,y1+2," []~~~[] ");
		if (ch==KDOWN) break; // 降下キーが押されるまで
		// 母船移動
		if (h1==1 && x1<35) x1++;
		if (h1==0 && x1>4)  x1--;
		// 方向転換
		if (x1==35) h1=0;
		if (x1== 4) h1=1;
		MoveFuyu();
		vwait(15);
	}
	
	// 宇宙船離脱(L160)
	for (i=0;i<10;i++) {
		MoveFuyu();
		if (i==5) {
			PCMplay(PCMopen,LENopen,-4);
			printxys(x1-1,y1+2,"L R"); // ゲート開く
			WaitPCM();
		} else	vwait(10);
	}
	printxys(x1  ,y1+1, "M" ); // 宇宙船消す
	printxys(x1-1,y1+2,"~~~"); // ゲート閉める
	// 初期の宇宙船の座標
	x2=x1;
	y2=y1+3;
	printxy(x2,y2,SHIP); // 宇宙船
	vwait(16);
	
	// 宇宙船下降(L200)
	while (1) {
		while (1) {
			/* キー入力 */
			ch=getky();
			
			if (y2>=19) break; // 最終着陸体制へ
			if (++cl==6) cl=0;
			if (cl!=0) {MoveFuyu(); MoveBosen();}
			if (scrn(x2,y2)!=SHIP) return(BreakShip());
			
			printxy(x2,y2  ,' '); // 元の場所を消す
			printxy(x2,y2+1,' ');
			// キー別処理
			i=1;
			switch(ch) {
				case KUP:
					if (cl==0) y2++;
					break;
				case KLEFT:
					if (cl==0 && x2>0 ) {x2--; y2++;}
					break;
				case KRIGHT:
					if (cl==0 && x2<39) {x2++; y2++;}
					break;
				case KLDOWN:
					if (x2>0 ) {x2--; y2++; i=0;}
					break;
				case KRDOWN:
					if (x2<39) {x2++; y2++; i=0;}
					break;
				case KDOWN:
				case 0:
					y2++;
					i=0;
					break;
			}
			printxy(x2,y2,SHIP);
			if (i) printxy(x2,y2+1,FIRE);
			vwait(18);
		}
		// 最終着陸体制(L400)
		printxy(x2,y2,' ');
		if (y2==19) printxy(x2,y2+1,' ');
		if (ch==KLEFT ) x2--;
		if (ch==KRIGHT) x2++;
		y2++;
		ch=scrn(x2,y2);
		if (ch!=' ') {
			if (y2==23) {
				// 着地
				if (ch==BASE2||ch==BASE1) {
					PCMplay(PCMchak,LENchak,-3);
					printxy(x2,--y2,SHIP);
					score(ch==BASE1? 150:50);
					WaitPCM();
					break; // 救出へ
				}
			}
			// 着地失敗
			return(BreakShip());
		}
		printxy(x2,y2,SHIP); // 最終着陸準備中
		vwait(18);
	}
	// 救出(L500)
	// 人が駆け寄ってくる
	if (h2<h3) { // 左の方が少ない -> 右から助け出す
		h3--;
		PrMAN(); // 人の表示
		// 人が駆け寄ってくる:←
		for (i=34;i>=x2;i--) {
			ch=scrn(i,y2+1);
			printxy(i,y2+1,MAN);
			vwait(10);
			printxy(i,y2+1,ch);
		}
		if (h3==0) {
			// 左右とも０になった：人がまた出てくる
			h2=H2INIT;
			h3=H3INIT;
			score(1000);
		}
	} else { // 右の方が少ないか両方同じ -> 左から助け出す
		if (h2>=1) {
			h2--;
			PrMAN(); // 人の表示
		}
		// 人が駆け寄ってくる:→
		for (i=5;i<=x2;i++) {
			ch=scrn(i,y2+1);
			printxy(i,y2+1,MAN);
			vwait(10);
			printxy(i,y2+1,ch);
		}
	}
	PCMplay(PCMman,LENman,-4);
	while (getky()==0); // 最初のキー入力待ち
	WaitPCM();
	// 宇宙船離陸
	y2--;
	printxy(x2,y2  ,SHIP);
	printxy(x2,y2+1,FIRE);
	cfuyu=UFO; // 浮遊物をUFOにする
	
	// 上昇・攻撃(L600)
	while (1) {
		while (1) {
			/* キー入力 */
			ch=getky();
			if (++cl==6) cl=0;
			if (y2<=5) break; // ドッキングへ
			MoveFuyu();
			BeamUp();
			MoveBosen();
			//BeamUp();	// 速すぎるので調整
			if (cl<4) {
				// UFOがミサイルを出す（下がスペースの時のみ）
				i=rand2(WX);
				if (scrn(i,7)==' ') {
					B_COLOR(TYELLOW|HLIGHT);
					printxy(i,6,MISS);
					B_COLOR(TWHITE);
				}
			}
			MoveMissile();
			BeamUp();
			if (scrn(x2,y2-1)!=' '||scrn(x2,y2)!=SHIP) return(BreakShip());
			printxy(x2,y2  ,' '); // 宇宙船元の位置を消す
			printxy(x2,y2+1,' ');
			//BeamUp();	// 速すぎるので調整
			switch (ch) {
				case KLEFT:
					if (x2>0) {
						x2--;
						y2--;
						printxy(x2,y2+1,FIRE);
						goto L650;
					}
					break;
				case KRIGHT:
					if (x2<39) {
						x2++;
						y2--;
						printxy(x2,y2+1,FIRE);
						goto L650;
					}
					break;
				case KUP:
					y2--;
					break;
				case KLDOWN:
					if (cl<3 && x2>0 ) x2--;
					break;
				case KRDOWN:
					if (cl<3 && x2<39) x2++;
					break;
				case KDOWN: // ビーム発射
					if (x3<0) {x3=x2; y3=y2-1;}
					break;
			}
			if (cl==0) {
				BeamUp();
				y2--;
			}
		    L650:;
			printxy(x2,y2,SHIP);
			vwait(16);
		}
		// ドッキング(L800)
		for (i=0;i<WX;i++) {
			if (scrn(i,3)==GATE) { // ゲートを開ける
				printxy(i,3,' ');
				printxy(i,2,GATE);
			}
		}
		printxy(x2,y2  ,' '); // 元の位置を消す
		printxy(x2,y2+1,' ');
		switch (ch) {
			case KLEFT:
				if (x2>0) x2--;
				break;
			case KUP:
				y2--;
				goto L840;
			case KRIGHT:
				if (x2<39) x2++;
				break;
		}
		if (cl==4) y2--;
	    L840:;
		i=scrn(x2,y2);
		if (i!=' ' && i!=GATE) break; // ドッキング失敗へ
		printxy(x2,y2,SHIP);
		if (scrn(x2,y2-1)==GATE && y2==3) {
			// ドッキング完了
			vwait(16);
			PCMplay(PCMdock,LENdock,-4);
			printxy(x2,y2  ,' ');
			printxy(x2,y2-1,SHIP);
			score(100*men); // 得点加算
			WaitPCM();
			vwait(5);
			if (++men>=MENMAX) men=1;
			return(2); // 面最初に戻る（面クリア）
		}
		vwait(16);
		if (y2<=1) return(BreakShip());
	}
	// ドッキング失敗（L890）
	if (y2!=1) {
		printxy(x2,y2,SHIP);
		// 人が落ちる
		PCMplay(PCMdown,LENdown,-4);
		i=y2;
		while (i<23 && scrn(x2,++i)==' ') {
			printxy(x2,i,DMAN);
			vwait(14);
			printxy(x2,i,' ');
		}
		y2=i;
		score(-200);
		// 人の位置で爆発させるため
		h4++; // 後で−１されるから
		WaitPCM();
	} // y2==1 : 宇宙船が爆発
	return(BreakShip());
}

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

int getky()
/* キー入力：複数キーの設定を可能にするため */
/* でも基本操作はテンキーで行う */
/* 今回はJOYSTICK対応なし */
{
int c;
	// 使うキー
	// 456(=789)
	// 123
	c=inkey2(1,0);
	switch (c) { /* カーソルキー対応コード変換 */
		case SKleft: /* left */
			c=KLEFT;
			break;
		case SKup: /* up */
			c=KUP;
			break;
		case SKright: /* right */
			c=KRIGHT;
			break;
		case SKdown: /* down */
			c=KDOWN;
			break;
	}
	c&=0xff;
	c=toupper(c);
	switch (c) {
		case '7':c=KLEFT;  break;
		case '8':c=KUP;    break;
		case '9':c=KRIGHT; break;
		case 'Z':c=KLDOWN; break;
		case 'X':c=KRDOWN; break;
		case ' ':c=KDOWN;  break;
		/* その他 */
		case CR:/* PANIC */
			{unint count[CMAX];
			int bsize,csize,f=0;
			unchar *bbuff,*cbuff;
			
			counttext3(0,0,95,31,count);
			calctext3(0,0,95,31,count,&bsize,&csize);
			bbuff=malloc(bsize+csize);
			if (bbuff==NULL) f=1; // メモリーが足りない
			else {
				cbuff=&bbuff[bsize];
				gettext3s(0,0,95,31,count,bbuff,cbuff);
			}
			curon();
			cls();
			spawnlp(P_WAIT,exec,exec,NULL,NULL);
			CRTMOD(16); // cwidth(96);
			if (f) { // メモリーが足りない時は不完全画面復帰
				pop_tvram();
				title();
			} else {
				puttext3(0,0,bbuff,cbuff);
				free(bbuff);
			}
			}
		case ESC:/* PAUSE */
			curon();
			center(WY+2,"ＰＡＵＳＥ");
			if (KFLUSHGC()=='!') { // キー入力待ち
		    case '!':/* BREAK */
				curon();
				exit(1);
				/* なんとサブルーチンからexit()しているのだ。 */
				/* あまりお勧めは出来ない技だからみなさんはまねしないでね！ */
			}
			center(WY+2,"　　　　　");
			curoff();
			break;
	}
	return(c);
}

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

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読み込み */
	LENbang=fmalloc(&PCMbang,"BOMB1.PCM",0,0);
	LENopen=fmalloc(&PCMopen,"BKTRASH.PCM",0,0);
	LENdock=fmalloc(&PCMdock,"SHOW.PCM",0,0);
	LENdown=fmalloc(&PCMdown,"SCRM_ML.PCM",0,0);
	LENpong=fmalloc(&PCMpong,"WHIP1.PCM",0,0);
	LENchak=fmalloc(&PCMchak,"CARBINE.PCM",0,0);
	LENman =fmalloc(&PCMman ,"SCRCH4.PCM",0,0);
	LENappl=fmalloc(&PCMappl,"APL.PCM",0,0);
	LENhiq =fmalloc(&PCMhiq ,"HIQ.PCM",0,0);
	
	// 画面関係
	CRTMOD(16); // cwidth(96);
	help_set(argv[0],0);
	
	do {
		/* 初期化 */
		curoff(); /* cursor off */
		disp();
		// 変数初期化
		sco=0;		/* 得点 */
		h2=H2INIT;	// 左側の人の数
		h3=H3INIT;	// 右側の人の数
		h4=H4INIT;	// 初期の宇宙船の数
		h4up=0;		// 宇宙船は増えていない
		men=1;		// 面
		//
		do { /* ゲーム本体 */
			// １機毎の初期化
			init1();
			// ゲーム本体
			ret=GameMain();
		} while (ret);
		
		/* ゲーム終了 */
		B_COLOR(TYELLOW|HLIGHT);
		message("☆☆ ＧＡＭＥ　ＯＶＥＲ ☆☆",4);
		B_COLOR(TWHITE);
		if (sco>hsc) {
			B_COLOR(TCYAN|REVERSE|HLIGHT);
			center(8,"＊＊　新記録！！　＊＊");
			B_COLOR(TWHITE);
			hsc=sco;
			hi_score();
			PCMplay(PCMappl,LENappl,-4);
		}
		center(10,"もう一度しますか？");
		curon();
		do {
			ret=KFLUSHGC(); // toupperマクロ化対応
			ret=toupper(ret);
		} while (ret!='Y' && ret!='N' && ret!=0x1b);
		WaitPCM();
	} while (ret=='Y');
	
	crlf();
	fp=fopen(RECHIGH,"wb");
	if (fp!=NULL) { /* hi-score write */
		fwrite(&hsc,sizeof(hsc),1,fp);
		fclose(fp);
	}
	/* ADPCMバッファー開放 */
	if (PCMbang!=NULL) free(PCMbang);
	if (PCMopen!=NULL) free(PCMopen);
	if (PCMdock!=NULL) free(PCMdock);
	if (PCMdown!=NULL) free(PCMdown);
	if (PCMpong!=NULL) free(PCMpong);
	if (PCMchak!=NULL) free(PCMchak);
	if (PCMman !=NULL) free(PCMman );
	if (PCMappl!=NULL) free(PCMappl);
	if (PCMhiq !=NULL) free(PCMhiq );
	exit(0);
}

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