/*
 *	game.c
 *
 *	クラックスもどき
 *
 *	* Sun Jul 29 23:59:59 JST 2018 Naoyuki Sawa
 *	- 1st リリース。
 */
#include "app.h"
//*****************************************************************************
//	定数
//*****************************************************************************
//ST_Tile.stat
#define TileStat_Blank			0					//未出現
#define TileStat_Move			1					//移動中
#define TileStat_Fall			2					//落下中
#define TileStat_Throw			3					//投げ返し中
#define TileStat_Max			TileStat_Throw
//-----------------------------------------------------------------------------
//ST_Stack.stat
#define StackStat_Blank			0					//空
#define StackStat_Tile			1					//タイル
#define StackStat_Erase			2					//消滅中
#define StackStat_Wire			3					//ワイヤー
#define StackStat_Max			StackStat_Wire
//-----------------------------------------------------------------------------
//ST_Game.stat
#define GameStat_Ready			0
#define GameStat_Move			1
#define GameStat_Erase			2
#define GameStat_Clear			3
#define GameStat_GameOver		4
#define GameStat_Max			GameStat_GameOver
//-----------------------------------------------------------------------------
//ST_Game.qualifyType
#define QualifyType_Klax		0
#define QualifyType_Diagonal		1
#define QualifyType_Tile		2
#define QualifyType_Points		3
#define QualifyType_Horizontal		4
#define QualifyType_Max			QualifyType_Horizontal
//-----------------------------------------------------------------------------
#define PRI__BG				0
#define PRI__TABLE			1000
#define PRI__DROPMETER			2000
#define PRI__POINT			3000
#define PRI__FALL			4000
#define PRI__HOLD			5000
#define PRI__STACK			6000
#define PRI__READY			7000
#define PRI__QUALIFY			8000
#define PRI__GAMEOVER			9000
#define PRI__SCORE			10000
//-----------------------------------------------------------------------------
#define COLOR_NUM			4					//色数
#define STEP_COUNT			4					//半回転分のステップ数
#define TABLE_WIDTH			5					//テーブルの幅(タイル数)
#define TABLE_DEPTH			20					//テーブルの奥行き(タイル数)
#define THROW_DEPTH			10					//投げ返し距離(タイル数)
#define HOLD_HEIGHT			5					//ホールドタイルの最大高さ
#define STACK_HEIGHT			5					//スタックタイルの最大高さ
#define FALL_HEIGHT			10					//落下タイルの最大高さ
#define TILE_NUM			(TABLE_WIDTH*TABLE_DEPTH)		//タイルの最大出現数	調整可
#define ERASE_TIME			SEC(1.0)				//消滅時間		調整可
#define READY_TIME			SEC(4.7)				//Ready時間		Game_Draw()での「<< ｸﾘｱ ﾊ ? >>」と「QualifyDesc」が最後に長く点灯した状態で抜けるようにReady時間の長さを調整しました。
#define GAMEOVER_TIME			SEC(9.7)				//GameOver時間
#define SCORE_MAX			999999					//スコアの最大値
#define SPEED_MAX			1.0					//速度の最大値
#define INTERVAL_MIN			(STEP_COUNT*1.0)			//出現間隔の最小値
#define DROPMETER_MAX			3					//ドロップメーターの最大値
#define SPEED_UP_RATE			1.005					//速度の変化率
#define INTERVAL_DOWN_RATE		0.995					//出現間隔の変化率
//*****************************************************************************
//	構造体
//*****************************************************************************
typedef struct _ST_Tile {
	unsigned char			stat;					//TileStat_*
	unsigned char			color;					//0〜COLOR_NUM-1
	unsigned char			x;					//0〜TABLE_WIDTH-1
	unsigned char			y;					//0〜FALL_HEIGHT-1
	unsigned char			z;					//0〜TABLE_DEPTH-1
	unsigned char			step;					//0〜STEP_COUNT-1
} ST_Tile;
//-----------------------------------------------------------------------------
typedef struct _ST_Stack {
	unsigned char			stat;					//StackStat_*
	unsigned char			color;					//0〜COLOR_NUM-1
} ST_Stack;
//-----------------------------------------------------------------------------
typedef struct _ST_Game {
	int				score;
	int				stage;					//1〜
	int				dropMeter;				//0〜3
	int				qualifyType;				//QualifyType_*
	int				qualifyValue;				//0〜
	//スクロール背景
	unsigned char			bg_x;					//0〜255。1/2してx座標と見なす。
	//--- ステージ開始時に、stat以降をクリアする ---
	int				stat;					//GameStat_*
	double				speed;					//0.0＜speed≦STEP_COUNT		ステージ開始時に初期化。クリアが長引くとだんだん増えて行く。	⇒ステージ中の加速はしない方が良いか？
	double				speed_sum;				//0.0≦speed_sum＜1.0			毎フレームspeedを加算し、整数部を取り出して各タイルのstepに加算する。
	double				interval;				//STEP_COUNT≦interval≦STEP_COUNT*9	ステージ開始時に初期化。クリアが長引くとだんだん減って行く。
	double				interval_sum;				//0.0≦interval＜interval		毎フレームspeedを加算し、interval以上になったら新しいタイルを出現する。
	//Ready
	int				ready_cnt;				//Readyカウンタ
	//Clear
	int				clear_step;				//Clearステップ				0=ウェイト,1=タイルボーナス計数,2=タイルボーナス加算,3=ウェイト,4=エンプティスペースボーナス計数,5=エンプティスペースボーナス加算,6=ウェイト,7=スコア加算,8=ウェイト,9=完了
	int				clear_cnt;				//Clear中の汎用カウンタ
	int				bonus;					//ポーナスポイント
	//GameOver
	int				gameover_cnt;				//GameOverカウンタ
	//パドル
	int				paddle_x;				//0〜TABLE_WIDTH-1
	int				hold_num;				//0〜HOLD_HEIGHT
	unsigned char			hold_color[HOLD_HEIGHT];		//0〜COLOR_NUM-1	[0]=底,…,[hold_num-1]=上
	//ドロップ
	int				drop_step;				//0=ドロップ無し,1〜STEP_COUNT-1=ドロップ中
	int				drop_color;				//0〜COLOR_NUM-1
	int				drop_x;					//0〜TABLE_WIDTH-1
	int				drop_y;					//0〜HOLD_HEIGHT-1
	//タイル
	ST_Tile				TBL_Tile[TILE_NUM];			//タイル
	//スタック
	ST_Stack			TBL_Stack[TABLE_WIDTH][STACK_HEIGHT];	//スタック		[][0]=底,…,[][STACK_HEIGHT-1]=上
	//消滅判定
	int				point;					//ポイント(連鎖含まず)		0〜				クリア中のタイルボーナス、エンプティスペースボーナス表示も兼ねる。
	int				chain_cnt;				//連鎖				0〜
	int				erase_cnt;				//消滅アニメーションカウンタ	0〜ERASE_TIME-1
	int				rgn_num[4];				//領域数
	ST_PzlRgn			TBL_Rgn[4][TABLE_WIDTH*STACK_HEIGHT];	//領域
} ST_Game;
//*****************************************************************************
//	定数データ
//*****************************************************************************
const unsigned short TBL_TileSnd[COLOR_NUM]={PhrNo_CAFFEE_SAUCER_PLACE1,PhrNo_CUP_PUT1,PhrNo_RICE_COOKER_CLOSE1,PhrNo_TEAPOT_CLOSE1};
const unsigned char TBL_X_Pri[TABLE_WIDTH]={0,1,2,1,0};
const unsigned char TBL_Color[COLOR_NUM]={0,2,3,1};	//少ない色数の時に、なるべく見分け易い色を優先して使う事にした。2色ならば{白,暗}、3色ならば{白,暗,黒}、4色ならば{白,暗,黒,明}。
const char TBL_Dir[4/*dir*/][2/*vx,vy*/]={{1,0},{0,1},{1,1},{-1,1}};
//□http://tips.retrogames.com/gamepage/klax.html
//	本当はこうだが↓	桁数を抑えるためにこうした↓
//Scoring:
//3 Vertical Klax: 50 points.			->	  5
//4 Vertical Klax: 10,000 points.		->	 10
//5 Vertical Klax: 15,000 points.		->	 15
//3 Horizontal Klax: 1,000 points.		->	 10
//4 Horizontal Klax: 5,000 points.		->	 50
//5 Horizontal Klax: 10,000 points.		->	100
//3 Diagonal Klax: 5,000 points.		->	 50
//4 Diagonal Klax: 10,000 points.		->	100
//5 Diagonal Klax: 20,000 points.		->	150
//Large 'X' Klax: 80,000 points.		->	無し
//Big Sandwich: 100,000 - 440,000 points.	->	無し
unsigned char TBL_Point[4/*dir*/][3/*len-3*/]={
	{ 10, 50,100},	//水平 Klax
	{  5, 10, 15},	//垂直 Horizontal
	{ 50,100,150},	//降斜 Diagonal
	{ 50,100,150},	//昇斜 Diagonal
};
//*****************************************************************************
//	変数データ
//*****************************************************************************
ST_Game		stGame;
int		hiscore;
int		stage_sel	= 1;		//開始ステージ		1〜100
int		color_num	= 3;		//色数			2〜COLOR_NUM
//*****************************************************************************
//	パーツ描画
//*****************************************************************************
void DrawTableTile(int c, int x, int z, int step) {
	int iSprNo, iPri;
	if(((unsigned)c >= COLOR_NUM) ||
	   ((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)z >= TABLE_DEPTH) ||
	   ((unsigned)step >= STEP_COUNT)) { DIE(); }
	iSprNo  =  SprNo_TABLETILE_0_0_0_0;
	iSprNo += (SprNo_TABLETILE_1_0_0_0 - SprNo_TABLETILE_0_0_0_0) * c;
	iSprNo += (SprNo_TABLETILE_0_1_0_0 - SprNo_TABLETILE_0_0_0_0) * x;
	iSprNo += (SprNo_TABLETILE_0_0_1_0 - SprNo_TABLETILE_0_0_0_0) * z;
	iSprNo += (SprNo_TABLETILE_0_0_0_1 - SprNo_TABLETILE_0_0_0_0) * step;
	iPri = PRI__TABLE;
	iPri += (TABLE_DEPTH - z) * TABLE_WIDTH * STEP_COUNT * 2;
	iPri +=                    TBL_X_Pri[x] * STEP_COUNT * 2;
	iPri +=                                         step * 2;
	iPri +=                                                0/*TableTile*/;
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//-----------------------------------------------------------------------------
void DrawThrowTile(int c, int x, int z) {
	int iSprNo, iPri;
	if(((unsigned)c >= COLOR_NUM) ||
	   ((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)z >= THROW_DEPTH)) { DIE(); }
	iSprNo  =  SprNo_THROWTILE_0_0_0;
	iSprNo += (SprNo_THROWTILE_1_0_0 - SprNo_THROWTILE_0_0_0) * c;
	iSprNo += (SprNo_THROWTILE_0_1_0 - SprNo_THROWTILE_0_0_0) * x;
	iSprNo += (SprNo_THROWTILE_0_0_1 - SprNo_THROWTILE_0_0_0) * z;
	iPri = PRI__TABLE;
	iPri += (TABLE_DEPTH - z) * TABLE_WIDTH * STEP_COUNT * 2;
	iPri +=                    TBL_X_Pri[x] * STEP_COUNT * 2;
	iPri +=                                    /*step*/0 * 2;
	iPri +=                                                1/*ThrowTile*/;
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//-----------------------------------------------------------------------------
void DrawHoldTile(int c, int x, int y, int step) {
	int iSprNo, iPri;
	if(((unsigned)c >= COLOR_NUM) ||
	   ((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)y >= HOLD_HEIGHT) ||
	   ((unsigned)step >= STEP_COUNT)) { DIE(); }
	iSprNo  =  SprNo_HOLDTILE_0_0_6_0;
	iSprNo += (SprNo_HOLDTILE_1_0_6_0 - SprNo_HOLDTILE_0_0_6_0) * c;
	iSprNo += (SprNo_HOLDTILE_0_1_6_0 - SprNo_HOLDTILE_0_0_6_0) * x;
	iSprNo += (SprNo_HOLDTILE_0_0_7_0 - SprNo_HOLDTILE_0_0_6_0) * y;
	iSprNo += (SprNo_HOLDTILE_0_0_6_1 - SprNo_HOLDTILE_0_0_6_0) * step;
	iPri = PRI__HOLD;
	iPri += (y + 1/*HoldTile*/) * TABLE_WIDTH * STEP_COUNT;
	iPri +=                      TBL_X_Pri[x] * STEP_COUNT;
	iPri +=                                           step;
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//-----------------------------------------------------------------------------
void DrawPaddle(int x, int y) {
	int iSprNo, iPri;
	if(((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)y >= HOLD_HEIGHT)) { DIE(); }
	iSprNo  =  SprNo_PADDLE_0_5;
	iSprNo += (SprNo_PADDLE_1_5 - SprNo_PADDLE_0_5) * x;
	iSprNo += (SprNo_PADDLE_0_6 - SprNo_PADDLE_0_5) * y;
	iPri = PRI__HOLD;
	iPri += (y + 0/*Paddle*/) * TABLE_WIDTH * STEP_COUNT;
	iPri +=                    TBL_X_Pri[x] * STEP_COUNT;
	iPri +=                                    /*step*/0;
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//-----------------------------------------------------------------------------
void DrawStackTile(int c, int x, int y) {
	int iSprNo, iPri;
	if(((unsigned)c >= COLOR_NUM) ||
	   ((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)y >= STACK_HEIGHT)) { DIE(); }
	iSprNo  =  SprNo_STACKTILE_0_0_1;
	iSprNo += (SprNo_STACKTILE_1_0_1 - SprNo_STACKTILE_0_0_1) * c;
	iSprNo += (SprNo_STACKTILE_0_1_1 - SprNo_STACKTILE_0_0_1) * x;
	iSprNo += (SprNo_STACKTILE_0_0_2 - SprNo_STACKTILE_0_0_1) * y;
	iPri = PRI__STACK;
	iPri += y * TABLE_WIDTH;
	iPri +=    TBL_X_Pri[x];
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//-----------------------------------------------------------------------------
void DrawStackWire(int x, int y) {
	int iSprNo, iPri;
	if(((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)y >= STACK_HEIGHT)) { DIE(); }
	iSprNo  =  SprNo_STACKWIRE_0_1;
	iSprNo += (SprNo_STACKWIRE_1_1 - SprNo_STACKWIRE_0_1) * x;
	iSprNo += (SprNo_STACKWIRE_0_2 - SprNo_STACKWIRE_0_1) * y;
	iPri = PRI__STACK;
	iPri += y * TABLE_WIDTH;
	iPri +=    TBL_X_Pri[x];
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//-----------------------------------------------------------------------------
void DrawFallTile(int c, int x, int y) {
	int iSprNo, iPri;
	if(((unsigned)c >= COLOR_NUM) ||
	   ((unsigned)x >= TABLE_WIDTH) ||
	   ((unsigned)y >= FALL_HEIGHT)) { DIE(); }
	iSprNo  =  SprNo_FALLTILE_0_0_1;
	iSprNo += (SprNo_FALLTILE_1_0_1 - SprNo_FALLTILE_0_0_1) * c;
	iSprNo += (SprNo_FALLTILE_0_1_1 - SprNo_FALLTILE_0_0_1) * x;
	iSprNo += (SprNo_FALLTILE_0_0_2 - SprNo_FALLTILE_0_0_1) * y;
	iPri = PRI__FALL;
	iPri += y * TABLE_WIDTH;
	iPri +=    TBL_X_Pri[x];
	CbkQue_sprite_draw(pCbkQue,
		iPri,
		0,
		0,
		iSprNo,
		DRW_NOMAL);
}
//*****************************************************************************
//	
//*****************************************************************************
int GetRndX() {
	int x = (unsigned)RND32(seed) % TABLE_WIDTH;
	return x;
}
//-----------------------------------------------------------------------------
int GetRndColor() {
	int c = (unsigned)RND32(seed) % color_num;
	return TBL_Color[c];
}
//*****************************************************************************
//	
//*****************************************************************************
ST_Tile* Tile_Alloc() {
	int i;
	for(i = 0; i < TILE_NUM; i++) {
		ST_Tile* pTile = &stGame.TBL_Tile[i];
		if(!pTile->stat) {
			memset(pTile, 0, sizeof(ST_Tile));
			return pTile;
		}
	}
	return NULL;
}
//-----------------------------------------------------------------------------
void Tile_Free(ST_Tile* pTile) {
	memset(pTile, 0, sizeof(ST_Tile));
}
//*****************************************************************************
//	
//*****************************************************************************
void SoundPlay(int iCh, int iPhrNo, int iAtt) {
	sound_play(iCh, sound_table[iPhrNo], 1);
	sound_att(iCh, iAtt);
}
//-----------------------------------------------------------------------------
void MusicPlay(int iMusNo) {
	PlayMusic(music_table[iMusNo]);
}
//*****************************************************************************
//	
//*****************************************************************************
void Game_Init() {
	//クリア
	memset(&stGame, 0, sizeof stGame);
	//開始ステージを格納
	stGame.stage = stage_sel;
}
//-----------------------------------------------------------------------------
void Stage_Init() {
	//stat以降をクリア
	memset(&stGame.stat, 0, sizeof stGame - offsetof(ST_Game, stat));
	//パドル初期化
	stGame.paddle_x = TABLE_WIDTH / 2;
	stGame.hold_color[stGame.hold_num++] = GetRndColor();	//開始時に一個持っている。(オリジナル版に準拠)
	//クリア条件を設定
	stGame.qualifyType = (stGame.stage - 1) % (QualifyType_Max + 1);	//QualifyType_*
//{{調整可
	{
		int i, j, k;
		i = j = k = (stGame.stage - 1) / (QualifyType_Max + 1);		//0〜19
				//                               |→51〜
		i = min(i, 9);	// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
		//
		j >>= 1;	// 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9
		j = min(j, 5);	// 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
		//
		k += 2;		// 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21
		k /= 3;		// 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7
		switch(stGame.qualifyType) {
		default:DIE();
		case QualifyType_Klax:
			stGame.qualifyValue =   3 + (  3 * i);	//3〜30
			SoundPlay(0, PhrNo_KLAX_WAVE, 0);
			break;
		case QualifyType_Diagonal:
			stGame.qualifyValue =   3 + (  2 * i);	//3〜21
			SoundPlay(0, PhrNo_DIAGONAL_WAVE, 0);
			break;
		case QualifyType_Tile:
			stGame.qualifyValue =  50 + (  5 * i);	//5〜95
			SoundPlay(0, PhrNo_TILE_WAVE, 0);
			break;
		case QualifyType_Points:
			stGame.qualifyValue = 100 + (100 * i);	//100〜1000
			SoundPlay(0, PhrNo_POINTS_WAVE, 0);
			break;
		case QualifyType_Horizontal:
			stGame.qualifyValue =   3 + (  2 * i);	//3〜21
			SoundPlay(0, PhrNo_HORIZONTAL_WAVE, 0);
			break;
		}
		stGame.speed = 0.5 + (0.1 * j);			//0.5〜1.0
		stGame.speed = min(stGame.speed, SPEED_MAX);
		stGame.interval = STEP_COUNT * (9 - k);		//STEP_COUNT*(9〜2)
		stGame.interval = max(stGame.interval, INTERVAL_MIN);
	}
//}}調整可
	stGame.interval_sum = stGame.interval - (stGame.speed * FPS);	//ステージ開始直後は、1秒後に出現するようにした。
}
//-----------------------------------------------------------------------------
void Game_Exec() {
	int erase_check = 0;
	int i, x, y;
	//スクロール背景
	if(stGame.stat == GameStat_Move) {
		stGame.bg_x--;
	}
	//タイル
	switch(stGame.stat) {
	default:DIE();
	case GameStat_Ready:
		{
			if(stGame.ready_cnt < READY_TIME) {
				if(stGame.ready_cnt >= SEC(0.1)/*調整可*/) {
					if(joy & TRG_AB) {
						stGame.ready_cnt = READY_TIME - 1;
					}
				}
				stGame.ready_cnt++;
			}
			if(stGame.ready_cnt >= READY_TIME) {
				if(!(joy & PAD_AB)) {	//開始時に一個持っているタイルを落としてしまわないように、ボタンが離されるまで待つ。
					stGame.stat++;
				}
			}
		}
		break;
	case GameStat_Move:
		{
			//進行
			{
				{
					static int Tile_compar(const void* _pTile1, const void* _pTile2) {	//GCC拡張機能
						const ST_Tile* pTile1 = _pTile1;
						const ST_Tile* pTile2 = _pTile2;
						if((pTile1->stat == TileStat_Move) && (pTile2->stat != TileStat_Move)) { return -1; }	//┬TileStat_Moveを優先する。
						if((pTile1->stat != TileStat_Move) && (pTile2->stat == TileStat_Move)) { return  1; }	//┘
						if(pTile1->z < pTile2->z) { return -1; }	//┬zが小さい方が近い。
						if(pTile1->z > pTile2->z) { return  1; }	//┘
						if(pTile1->step < pTile2->step) { return  1; }	//┬stepが小さい方が遠い。
						if(pTile1->step > pTile2->step) { return -1; }	//┘
						return 0;
					}
					//TBL_Tile[0〜3]をタイル音の発生源とするために、Moveを優先して近い順にソートする。
					qsort(stGame.TBL_Tile, ARRAY_SIZE(stGame.TBL_Tile), sizeof stGame.TBL_Tile[0], Tile_compar);
				}
				{
					int step_add;
					{
						double iptr;
						stGame.speed_sum += stGame.speed;
						stGame.speed_sum = modf(stGame.speed_sum, &iptr);
						step_add = iptr;
					}
					for(i = 0; i < TILE_NUM; i++) {
						ST_Tile* pTile = &stGame.TBL_Tile[i];
						if(pTile->stat) {
							switch(pTile->stat) {
							default:DIE();
							case TileStat_Move:
								{
									if(joy & PAD_DN) {
										pTile->step = STEP_COUNT;
									} else {
										pTile->step += step_add;
									}
									if(pTile->step >= STEP_COUNT) {
										while(pTile->step >= STEP_COUNT) {
											pTile->step -= STEP_COUNT;
											if(pTile->z) {
												pTile->z--;
												if(i < 4) {
													SoundPlay(i, TBL_TileSnd[pTile->color], pTile->z * 16/*調整可*/ / TABLE_DEPTH);
												}
											} else {
												if((stGame.paddle_x == pTile->x) && (stGame.hold_num < HOLD_HEIGHT)) {
													stGame.hold_color[stGame.hold_num++] = pTile->color;
													Tile_Free(pTile);
													//ホールド音
													SoundPlay(4, PhrNo_CURSOR7, 0);
													{
														//難易度上昇
														stGame.speed *= SPEED_UP_RATE;
														stGame.speed = min(stGame.speed, SPEED_MAX);
														stGame.interval *= INTERVAL_DOWN_RATE;
														stGame.interval = max(stGame.interval, INTERVAL_MIN);
														//クリア条件減算
														switch(stGame.qualifyType) {
														default:DIE();
														case QualifyType_Klax:
															/** no job **/
															break;
														case QualifyType_Diagonal:
															/** no job **/
															break;
														case QualifyType_Tile:
															stGame.qualifyValue--;
															break;
														case QualifyType_Points:
															/** no job **/
															break;
														case QualifyType_Horizontal:
															/** no job **/
															break;
														}
														stGame.qualifyValue = max(stGame.qualifyValue, 0);
													}
												} else {
													pTile->stat = TileStat_Fall;
													pTile->y = FALL_HEIGHT - 1;
													if(stGame.dropMeter < DROPMETER_MAX) {
														stGame.dropMeter++;
														if(stGame.dropMeter < DROPMETER_MAX) {
															//ミス音
															SoundPlay(7, PhrNo_SWORDMAN_DAMAGE2, 8);
														} else {
															//ゲームオーバー音
															SoundPlay(7, PhrNo_SWORDMAN_DEATH1, 8);
														}
													}
												}
												break;
											}
										}
									}
								}
								break;
							case TileStat_Fall:
								{
									if(pTile->y) {
										pTile->y--;
									} else {
										Tile_Free(pTile);
									}
								}
								break;
							case TileStat_Throw:
								{
									if(++pTile->z >= THROW_DEPTH) {
										pTile->stat = TileStat_Move;
										pTile->step = 0;
									}
								}
								break;
							}
						}
					}
				}
			}
			//出現
			{
				if(joy & PAD_DN) {
					stGame.interval_sum += STEP_COUNT;
				} else {
					stGame.interval_sum += stGame.speed;
				}
				while(stGame.interval_sum >= stGame.interval) {
					stGame.interval_sum -= stGame.interval;
					{
						ST_Tile* pTile = Tile_Alloc();
						if(pTile) {
							pTile->stat = TileStat_Move;
							pTile->color = GetRndColor();
							pTile->x = GetRndX();
							pTile->z = TABLE_DEPTH - 1;
						}
					}
				}
			}
		}
		break;
	case GameStat_Erase:
		{
			stGame.erase_cnt++;
			if(stGame.erase_cnt >= ERASE_TIME) {
				stGame.erase_cnt = 0;
				//落下
				{
					int down_snd = 0;
					for(x = 0; x < TABLE_WIDTH; x++) {
						int ydst = 0;
						for(y = 0; y < STACK_HEIGHT; y++) {
							ST_Stack* pStack = &stGame.TBL_Stack[x][y];
							if(pStack->stat) {
								switch(pStack->stat) {
								default:DIE();
								case StackStat_Tile:
									if(y != ydst) {
										if(ydst >= STACK_HEIGHT) { DIE(); }
										stGame.TBL_Stack[x][ydst] = *pStack;
										memset(pStack, 0, sizeof(ST_Stack));
										down_snd = 1;
									}
									ydst++;
									break;
								case StackStat_Erase:
									memset(pStack, 0, sizeof(ST_Stack));
									break;
								//case StackStat_Wire:
								}
							}
						}
					}
					if(down_snd) {
						//落下音
						SoundPlay(4, PhrNo_DRUM_JAPANESE1, 8/*落下と同時に消滅音が鳴るので消滅音が聞こえ易いように小さくした*/);
					}
				}
				erase_check = 1;
			}
		}
		break;
	case GameStat_Clear:
		{
			switch(stGame.clear_step) {
			default:DIE();
			case 0:	//ウェイト
				{
					if(++stGame.clear_cnt >= SEC(1.0)) {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 1:	//タイルボーナス計数
				{
					int i, flag = 0;
					if((unsigned)(stGame.clear_cnt++) % 3) { break; }
					for(i = TILE_NUM - 1; i >= 0; i--) {
						ST_Tile* pTile = &stGame.TBL_Tile[i];
						if(pTile->stat) {
							Tile_Free(pTile);
							stGame.point += 5;
							flag = 1;
							//計数音
							SoundPlay(4, PhrNo_SOCCER_BALL1, 0);
							break;
						}
					}
					if(!flag) {
						if(stGame.drop_step) {
							stGame.drop_step = 0;
							stGame.point += 5;
							flag = 1;
							//計数音
							SoundPlay(4, PhrNo_SOCCER_BALL1, 0);
						}
					}
					if(!flag) {
						if(stGame.hold_num) {
							stGame.hold_num--;
							stGame.point += 5;
							flag = 1;
							//計数音
							SoundPlay(4, PhrNo_SOCCER_BALL1, 0);
						}
					}
					if(!flag) {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 2:	//タイルボーナス加算
				{
					if(stGame.point) {
						int tmp = min(stGame.point, 5);
						stGame.point -= tmp;
						stGame.bonus += tmp;
						//加算音
						SoundPlay(4, PhrNo_CURSOR9, 0);
					} else {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 3:	//ウェイト
				{
					if(++stGame.clear_cnt >= SEC(0.5)) {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 4:	//エンプティスペースボーナス計数
				{
					int x, y, flag = 0;
					for(y = STACK_HEIGHT - 1; y >= 0; y--) {
						for(x = 0; x < TABLE_WIDTH; x++) {
							ST_Stack* pStack = &stGame.TBL_Stack[x][y];
							if(!pStack->stat) {
								if(!flag) {
									pStack->stat = StackStat_Wire;
									stGame.point += 10;
									flag = 1;
									//計数音
									SoundPlay(4, PhrNo_SOCCER_BALL1, 0);
								}
							}
						}
					}
					if(!flag) {
						for(y = STACK_HEIGHT - 1; y >= 0; y--) {
							for(x = 0; x < TABLE_WIDTH; x++) {
								ST_Stack* pStack = &stGame.TBL_Stack[x][y];
								if(pStack->stat == StackStat_Wire) {
									memset(pStack, 0, sizeof(ST_Stack));
								}
							}
						}
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 5:	//エンプティスペースボーナス加算
				{
					if(stGame.point) {
						int tmp = min(stGame.point, 10);
						stGame.point -= tmp;
						stGame.bonus += tmp;
						//加算音
						SoundPlay(4, PhrNo_CURSOR9, 0);
					} else {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 6:	//ウェイト
				{
					if(++stGame.clear_cnt >= SEC(0.5)) {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 7:	//ボーナス加算
				{
					if(stGame.bonus) {
						int tmp = min(stGame.bonus, 10);
						stGame.bonus -= tmp;
						stGame.score += tmp;
						//加算音
						SoundPlay(4, PhrNo_CURSOR9, 0);
					} else {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 8:	//ウェイト
				{
					if(++stGame.clear_cnt >= SEC(1.0)) {
						stGame.clear_cnt = 0;
						stGame.clear_step++;
					}
				}
				break;
			case 9:	//完了
				/** no job **/
				break;
			}
		}
		break;
	case GameStat_GameOver:
		{
			//進行(落下のみ)
			{
				{
					for(i = 0; i < TILE_NUM; i++) {
						ST_Tile* pTile = &stGame.TBL_Tile[i];
						if(pTile->stat) {
							switch(pTile->stat) {
							default:DIE();
							case TileStat_Move:
								{
									/** no job **/
								}
								break;
							case TileStat_Fall:
								{
									if(pTile->y) {
										pTile->y--;
									} else {
										Tile_Free(pTile);
									}
								}
								break;
							case TileStat_Throw:
								{
									/** no job **/
								}
								break;
							}
						}
					}
				}
			}
			if(stGame.gameover_cnt < GAMEOVER_TIME) {
				if(stGame.gameover_cnt >= SEC(1.0)/*調整可*/) {
					if(joy & TRG_AB) {
						stGame.gameover_cnt = GAMEOVER_TIME - 1;
					}
				}
				stGame.gameover_cnt++;
			}
		}
		break;
	}
	//パドル
	if((stGame.stat == GameStat_Move) || (stGame.stat == GameStat_Erase)/*アクティブ連鎖*/) {
		//パドル移動
		if((joy & TRG_LF) && (stGame.paddle_x >               0)) { stGame.paddle_x--; }
		if((joy & TRG_RI) && (stGame.paddle_x < TABLE_WIDTH - 1)) { stGame.paddle_x++; }
		//ドロップ中ならば…
		if(stGame.drop_step) {
			stGame.drop_step++;
			//ドロップ完了ならば…
			if(stGame.drop_step >= STEP_COUNT) {
				stGame.drop_step = 0;
				for(y = 0; y < STACK_HEIGHT; y++) {
					ST_Stack* pStack = &stGame.TBL_Stack[stGame.drop_x][y];
					if(!pStack->stat) {
						pStack->stat = StackStat_Tile;
						pStack->color = stGame.drop_color;
						//ドロップ音
						SoundPlay(4, PhrNo_CURSOR8, 0);
						break;
					}
				}
				if(y >= STACK_HEIGHT) { DIE(); }	//バグ
				//移動中ならば(=消滅中でなければ)…
				if(stGame.stat == GameStat_Move) {
					erase_check = 1;
				}
			}
		//ドロップ中でなければ…
		} else {
			//A,又は,Bボタンが押されたら…
			if(joy & TRG_AB) {
				//ホールドタイルが有れば…
				if(stGame.hold_num) {
					ST_Stack* pStack = &stGame.TBL_Stack[stGame.paddle_x][STACK_HEIGHT - 1];
					//スタックに空きが無ければ…
					if(pStack->stat) {
						//警告音
						SoundPlay(4, PhrNo_CANCEL2, 8);
					//スタックに空きが有れば…
					} else {
						stGame.hold_num--;
						stGame.drop_step = 1;
						stGame.drop_color = stGame.hold_color[stGame.hold_num];
						stGame.drop_x = stGame.paddle_x;
						stGame.drop_y = stGame.hold_num;
						if(stGame.drop_y < (HOLD_HEIGHT - 2)) { stGame.drop_y = (HOLD_HEIGHT - 2); }	//ホールド数が最大だった場合は一番上のタイルがテーブルよりも上、それ以外はテーブルの高さという表示上の特例。(オリジナル版に準拠)
					}
				}
			}
		}
		//投げ返し
		if(stGame.stat == GameStat_Move) {	//オリジナル版は消滅中にも投げ返しを開始出来るようだが、投げ返した瞬間にタイルが止まって見た目が悪いので、当プログラムでは投げ返し自体を出来ないようにする事にした。
			//上ボタンが押されたら…
			if(joy & TRG_UP) {
				//ホールドタイルが有れば…
				if(stGame.hold_num) {
					stGame.hold_num--;
					{
						ST_Tile* pTile = Tile_Alloc();
						if(pTile) {
							pTile->stat = TileStat_Throw;
							pTile->color = stGame.hold_color[stGame.hold_num];
							pTile->x = stGame.paddle_x;
							//投げ返し音
							SoundPlay(4, PhrNo_CURSOR4, 0);
						}
					}
				}
			}

		}
	}
	//消滅判定
	if(erase_check) {
		static int fnGetColor(int x, int y, void* user_data) {	//GCC拡張機能
			if((unsigned)x >= ARRAY_SIZE(stGame.TBL_Stack   )) { DIE(); }
			if((unsigned)y >= ARRAY_SIZE(stGame.TBL_Stack[x])) { DIE(); }
			{
				ST_Stack* pStack = &stGame.TBL_Stack[x][y];
				return pStack->stat ? (pStack->color + 1) : 0;
			}
		}
		int dir, rgn_sum = 0;
		for(dir = 0; dir < 4; dir++) {
			stGame.rgn_num[dir] = PzlUtl_GetLin(
				stGame.TBL_Rgn[dir],
				TABLE_WIDTH,
				STACK_HEIGHT,
				dir,
				3,
				fnGetColor,
				NULL);
			rgn_sum += stGame.rgn_num[dir];
		}
		if(rgn_sum) {
			stGame.stat = GameStat_Erase;
			stGame.chain_cnt++;
			for(dir = 0; dir < 4; dir++) {
				for(i = 0; i < stGame.rgn_num[dir]; i++) {
					ST_PzlRgn* pRgn = &stGame.TBL_Rgn[dir][i];
					int n = pRgn->len;
					if((n < 3) || (n > 5)) { DIE(); }	//バグ
					{
						//スコア加算
						stGame.point = TBL_Point[dir][n - 3];
						stGame.score += (stGame.point * stGame.chain_cnt);
						stGame.score = min(stGame.score, SCORE_MAX);
						//クリア条件減算
						switch(stGame.qualifyType) {
						default:DIE();
						case QualifyType_Klax:
							stGame.qualifyValue -= (n - 2);
							break;
						case QualifyType_Diagonal:
							if(dir >= 2/*降斜or昇斜*/) {
								stGame.qualifyValue -= (n - 2);
							}
							break;
						case QualifyType_Tile:
							/** no job **/
							break;
						case QualifyType_Points:
							stGame.qualifyValue -= (stGame.point * stGame.chain_cnt);
							break;
						case QualifyType_Horizontal:
							if(dir == 0/*水平*/) {
								stGame.qualifyValue -= (n - 2);
							}
							break;
						}
						stGame.qualifyValue = max(stGame.qualifyValue, 0);
					}
					x = pRgn->head % TABLE_WIDTH;
					y = pRgn->head / TABLE_WIDTH;
					do {
						if((unsigned)x >= ARRAY_SIZE(stGame.TBL_Stack   )) { die("%d,%d", x, y);DIE(); }
						if((unsigned)y >= ARRAY_SIZE(stGame.TBL_Stack[x])) { die("%d,%d", x, y);DIE(); }
						{
							ST_Stack* pStack = &stGame.TBL_Stack[x][y];
							switch(pStack->stat) {
							default:DIE();
							case StackStat_Tile:
								pStack->stat = StackStat_Erase;
								break;
							case StackStat_Erase:
								/** no job **/
								break;
							//case StackStat_Wire:
							}
						}
						x += TBL_Dir[dir][0/*vx*/];
						y += TBL_Dir[dir][1/*vy*/];
					} while(--n);
				}
			}
			//消滅音
			if(stGame.rgn_num[2] || stGame.rgn_num[3]) {
				MusicPlay(MusNo_DIAGONAL);
			} else if(stGame.rgn_num[0]) {
				MusicPlay(MusNo_HORIZONTAL);
			} else {
				MusicPlay(MusNo_VERTICAL);
			}
		} else {
			stGame.stat = GameStat_Move;
			stGame.point = 0;
			stGame.chain_cnt = 0;
		}
	}
	//クリア判定、ゲームオーバー判定
	if(stGame.stat == GameStat_Move) {
		//クリアならば…
		if(!stGame.qualifyValue) {
			stGame.stat = GameStat_Clear;
			//クリアと同時にドロップメーターが最大になった場合は一つ戻す事にした。
			if(stGame.dropMeter == DROPMETER_MAX) {
				stGame.dropMeter--;
			}
			//クリア音
			SoundPlay(7, PhrNo_CLAPPING_HANDS1, 0);
		//クリアでなければ…
		} else {
			//ゲームオーバー判定
			if(stGame.dropMeter == DROPMETER_MAX) {
				stGame.stat = GameStat_GameOver;
			}
		}
	}
}
//-----------------------------------------------------------------------------
void Game_Draw() {
	//常時
	{
		static const unsigned char TBL_c[]={
			0,	//SprNo_BG1
			1,	//SprNo_BG2
			1,	//SprNo_BG3
			2,	//SprNo_BG4
			1,	//SprNo_BG5
			3,	//SprNo_BG6
			1};	//SprNo_BG7
		int i, x, y;
		//スクロール背景を描く。
		if(stGame.stage < 1) { DIE(); }
		i = ((stGame.stage - 1) / (QualifyType_Max + 1)) % 7;	//0〜6
		x = stGame.bg_x / 2;
		do {
			CbkQue_sprite_draw(pCbkQue,
				PRI__BG,
				x,
				0,
				SprNo_BG1 + i,	//SprNo_BG1〜SprNo_BG7
				DRW_NOMAL);
			x -=  128;
		} while(x >= -128);
		//スクロール背景の下の空き領域を塗りつぶす。
		CbkQue_render_rectangle_fill(pCbkQue,
			PRI__BG,
			&render,
			0,
			88,
			88,
			128 - 88,
			TBL_c[i]);
		//テーブルを描く。
		CbkQue_sprite_draw(pCbkQue,
			PRI__TABLE,
			0,
			0,
			SprNo_TABLE,
			DRW_NOMAL);
		//タイルを描く。
		for(i = 0; i < TILE_NUM; i++) {
			ST_Tile* pTile = &stGame.TBL_Tile[i];
			if(pTile->stat) {
				switch(pTile->stat) {
				default:DIE();
				case TileStat_Move:
					{
						DrawTableTile(pTile->color, pTile->x, pTile->z, pTile->step);
					}
					break;
				case TileStat_Fall:
					{
						DrawFallTile(pTile->color, pTile->x, pTile->y);
					}
					break;
				case TileStat_Throw:
					{
						DrawThrowTile(pTile->color, pTile->x, pTile->z);
					}
					break;
				}
			}
		}
		//パドルを描く。
		y = HOLD_HEIGHT - stGame.hold_num;
		if(y) { y--; }	//ホールド数が最大だった場合は一番上のタイルがテーブルよりも上、それ以外はテーブルの高さという表示上の特例。(オリジナル版に準拠)
		DrawPaddle(stGame.paddle_x, y);
		//ホールドタイルを描く。
		for(i = 0; i < stGame.hold_num; i++) {
			DrawHoldTile(stGame.hold_color[i], stGame.paddle_x, y, 0);
			y++;
		}
		//ドロップタイルを描く。
		if(stGame.drop_step) {
			DrawHoldTile(stGame.drop_color, stGame.drop_x, stGame.drop_y, stGame.drop_step);
		}
		//スタックを描く。
		CbkQue_sprite_draw(pCbkQue,
			PRI__STACK,
			0,
			0,
			SprNo_STACK,
			DRW_NOMAL);
		//スタックタイルを描く。
		for(x = 0; x < TABLE_WIDTH; x++) {
			for(y = 0; y < STACK_HEIGHT; y++) {
				ST_Stack* pStack = &stGame.TBL_Stack[x][y];
				if(pStack->stat) {
					switch(pStack->stat) {
					default:DIE();
					case StackStat_Tile:
						{
							DrawStackTile(pStack->color, x, y);
						}
						break;
					case StackStat_Erase:
						{
							if(stGame.erase_cnt & 1) {
								DrawStackTile(pStack->color, x, y);
							}
						}
						break;
					case StackStat_Wire:
						{
							DrawStackWire(x, y);
						}
						break;
					}
				}
			}
		}
		//ドロップメーターを描く。
		for(i = 0; i < stGame.dropMeter; i++) {
			CbkQue_render_rectangle_fill(pCbkQue,
				PRI__DROPMETER,
				&render,
				24 + (14 * i),
				71,
				12,
				2,
				0);
		}
		//ポイントを描く。
		if(stGame.point ||
		 ((stGame.stat == GameStat_Clear) && stGame.clear_step)) {	//ボーナス計数,及び,加算中は0でも描く
			x = 24;
			y = 82;
			CbkQue_render_printf(pCbkQue,
				PRI__POINT,
				&render,
				x,
				y,
				2,
				0,
				"%10d", stGame.point);
			if(stGame.chain_cnt >= 2) {
				CbkQue_render_printf(pCbkQue,
					PRI__POINT,
					&render,
					x,
					y,
					2,
					0,
					"%4dx", stGame.chain_cnt);
			}
		}
		//スコアを描く。
		CbkQue_render_printf_framed(pCbkQue,
			PRI__QUALIFY,
			&render,
			DISP_X - (4 * 6) - 2,
			1,
			3,
			0x331,
			"%6d", hiscore);
		CbkQue_render_printf_framed(pCbkQue,
			PRI__QUALIFY,
			&render,
			DISP_X - (4 * 6) - 2,
			1 + 7,
			3,
			0x330,
			"%6d", stGame.score);
	}
	//Clear中の初期ウェイト以降ならば…
	if((stGame.stat == GameStat_Clear) && stGame.clear_step) {
		//ボーナスポイントを描く。
		CbkQue_sprite_draw(pCbkQue,
			PRI__QUALIFY,
			0,
			0,
			SprNo_BONUS,
			DRW_NOMAL);
		CbkQue_render_printf(pCbkQue,
			PRI__QUALIFY,
			&render,
			42,
			121,
			2,
			0,
			"%8d", stGame.bonus);
	//Clear中の初期ウェイト以降以外ならば…
	} else {
		//クリア条件を描く。
		CbkQue_sprite_draw(pCbkQue,
			PRI__QUALIFY,
			0,
			0,
			SprNo_QUALIFY_0 + stGame.qualifyType,	//SprNo_QUALIFY_0〜SprNo_QUALIFY_4
			DRW_NOMAL);
		CbkQue_render_printf(pCbkQue,
			PRI__QUALIFY,
			&render,
			42,
			121,
			2,
			0,
			"%8d", stGame.qualifyValue);
	}
	//Ready
	if(stGame.stat == GameStat_Ready) {
		static const char* const TBL_QualifyName[]={
			"KLAX",
			"DIAGONAL",
			"TILE",
			"POINTS",
			"HORIZONTAL",
		};
		static const char* const TBL_QualifyDesc[]={
			"ﾀｲﾙｦ %d ｶｲ ｿﾛｴﾙ",
			"ﾅﾅﾒﾆ %d ｶｲ ｿﾛｴﾙ",
			"ﾀｲﾙｦ %d ｺ ｳｹﾙ",
			"ｽｺｱｦ %d ﾃﾝ ﾄﾙ",
			"ﾖｺﾆ %d ｶｲ ｿﾛｴﾙ",
		};
		char buf[32];
		int x, y, c;
		const char* p;
		x = 10;
		y = 30;
		CbkQue_render_rectangle(pCbkQue,
			PRI__READY,
			&render,
			x - 1,
			y - 1,
			DISP_X - (x * 2) + 2,
			DISP_Y - (y * 2) + 2,
			1);
		CbkQue_render_rectangle_fill(pCbkQue,
			PRI__READY,
			&render,
			x,
			y,
			DISP_X - (x * 2),
			DISP_Y - (y * 2),
			3);
		//QualifyName
		p = TBL_QualifyName[stGame.qualifyType];
		x = (DISP_X - (5 * strlen(p))) / 2;
		y = 36;
		c = 2;
		while(*p) {
			CbkQue_render_font(pCbkQue, PRI__READY, &render, x, y, *p, 0, c);
			p++;
			x += 5;
			c = !c;
		}
		//WAVE
		p = "WAVE";
		x = (DISP_X - (5 * strlen(p))) / 2;
		y += 15;
		c = 2;
		while(*p) {
			CbkQue_render_font(pCbkQue, PRI__READY, &render, x, y, *p, 0, c);
			p++;
			x += 5;
			c = !c;
		}
		//WAVE番号
		sprintf(buf, "%d", stGame.stage);
		p = buf;
		x = (DISP_X - (5 * strlen(p))) / 2;
		y += 10;
		CbkQue_render_string(pCbkQue, PRI__READY, &render, x, y, p, 0, 0);
		//マーク
		CbkQue_sprite_draw(pCbkQue, PRI__READY, (DISP_X / 2) - 23, y - 1, SprNo_READY, DRW_NOMAL);
		CbkQue_sprite_draw(pCbkQue, PRI__READY, (DISP_X / 2) + 22, y - 1, SprNo_READY, DRW_REVX);
		if(stGame.ready_cnt % SEC(1.0) <= SEC(0.7)) {
			//<< ｸﾘｱ ﾊ ? >>
			p = "<< ｸﾘｱ ﾊ ? >>";
			sprintf(buf, p, stGame.qualifyValue);
			p = buf;
			x = (DISP_X - (4 * strlen(p))) / 2;
			y += 15;
			CbkQue_render_string(pCbkQue, PRI__READY, &render, x, y, p, 2, 0);
			//QualifyDesc
			p = TBL_QualifyDesc[stGame.qualifyType];
			sprintf(buf, p, stGame.qualifyValue);
			p = buf;
			x = (DISP_X - (4 * strlen(p))) / 2;
			y += 10;
			CbkQue_render_string(pCbkQue, PRI__READY, &render, x, y, p, 2, 0);
		}
	}
	//GameOver
	if(stGame.stat == GameStat_GameOver) {
		if(stGame.gameover_cnt >= SEC(1.0)) {
			int x, y;
			const char* p;
			x = 24;
			y = 57;
			CbkQue_render_rectangle(pCbkQue,
				PRI__READY,
				&render,
				x - 1 + 1/*調整可*/,
				y - 1 - 5/*調整可*/,
				DISP_X - (x * 2) + 2 - 1/*調整可*/,
				DISP_Y - (y * 2) + 2 - 1/*調整可*/,
				1);
			CbkQue_render_rectangle_fill(pCbkQue,
				PRI__READY,
				&render,
				x + 1/*調整可*/,
				y - 5/*調整可*/,
				DISP_X - (x * 2) - 1/*調整可*/,
				DISP_Y - (y * 2) - 1/*調整可*/,
				3);
			if(stGame.gameover_cnt % SEC(1.0) <= SEC(0.7)) {
				//GAMEOVER
				p = "GAMEOVER";
				x = (DISP_X - (4 * strlen(p))) / 2 + 1/*調整可*/;
				y = (DISP_Y / 2) - 3 - 5/*調整可*/;
				CbkQue_render_string(pCbkQue, PRI__GAMEOVER, &render, x, y, p, 2, 0);
			}
		}
	}
}
//-----------------------------------------------------------------------------
void Game_Run() {
	//ゲーム初期化
	Game_Init();
	for(;;) {
		//ステージ初期化
		Stage_Init();
		for(;;) {
			schedule();
			Game_Exec();
			Game_Draw();
			if(stGame.score > hiscore) { hiscore = stGame.score; }
			//クリア判定
			if(stGame.stat == GameStat_Clear) {
				if(stGame.clear_step == 9/*完了*/) {
					break;
				}
			}
			//ゲームオーバー判定
			if(stGame.stat == GameStat_GameOver) {
				if(stGame.gameover_cnt >= GAMEOVER_TIME) {
					return;
				}
			}
		}
		//ステージを進める。
		if(stGame.stage < 100) {
			stGame.stage++;
		}
	}
}
//*****************************************************************************
//	
//*****************************************************************************
void Demo_Run() {
	int StartDelay = 0, iTitleAnm = 0, sel = 0;
	int iPri, x, y, iSprNo, param, type, color;
	for(;;) {
		schedule();
		surface_clear(&surface, 3);
		//1P
		{
			iPri	= 0;
			x	= DISP_X - 32;
			y	= 2;
			type	= 2;
			color	= 2;
			CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color, "1P%06d", stGame.score);
			color	= 0;
			CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color, "1P%6d",  stGame.score);
		}
		//HI
		{
			iPri	= 0;
			x	= 1;
			y	= 2;
			type	= 2;
			color	= 2;
			CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color, "HI%06d", hiscore);
			color	= 0;
			CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color, "HI%6d",  hiscore);
		}
		//TITLE
		{
			iPri	= 0;
			x	= 0;
			y	= 26;
			iSprNo	= AnmSeqNo_GetVal(TBL_AnmSeqNo, AnmSeqNo_TITLE, iTitleAnm + 1, &iTitleAnm);
			param	= DRW_NOMAL;
			CbkQue_sprite_draw(pCbkQue, 0, x, y, iSprNo, param);
			x	= 65;
			y	= 47;
			CbkQue_render_string(pCbkQue, iPri, &render, x, y, "ﾓﾄｷ", 2, 1);
			x	+= 2;
			y	-= 2;
			CbkQue_render_string(pCbkQue, iPri, &render, x, y, " ﾞ ", 2, 1);
		}
		//STAGE
		{
			iPri	= 0;
			x	= (DISP_X - (4 * 12)) / 2;
			y	= 68;
			type	= 2;
			color	= 0;
			CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color,
			    //	"%c STAGE%3d %c",
				"%c WAVE %3d %c",
				((sel == 0) && !StartDelay && (stage_sel >   1)) ? '<' : ' ',
				                 stage_sel,
				((sel == 0) && !StartDelay && (stage_sel < 100)) ? '>' : ' ');
		}
		//COLOR
		{
			iPri	= 0;
			x	= (DISP_X - (4 * 12)) / 2;
			y	= 74;
			type	= 2;
			color	= 0;
			CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color,
				"%c COLOR%3d %c",
				((sel == 1) && !StartDelay && (color_num >         2)) ? '<' : ' ',
				                 color_num,
				((sel == 1) && !StartDelay && (color_num < COLOR_NUM)) ? '>' : ' ');
		}
		//PRESS A or B TO START
		//PRESS SELECT TO QUIT
		{
			iPri	= 0;
			x	= (DISP_X - (4 * 18)) / 2;
			y	= 98;
			type	= 2;
			color	= 0;
			if(!(StartDelay & 1)) {
				CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color, "PRESS A/B TO START");
			}
			y	+= 6;
			color	= 1;
			if(!StartDelay) {
				CbkQue_render_printf(pCbkQue, iPri, &render, x, y, type, color, "PRESS SEL TO QUIT ");
			}
		}
		if(!StartDelay) {
			if(joy & TRG_UD) {
				sel = !sel;
				SoundPlay(0, PhrNo_CURSOR8, 8);
			}
			if(sel == 0) {
				if(joy & TRG_LF) {
					if(stage_sel > 1) {
						stage_sel--;
						SoundPlay(0, PhrNo_CURSOR8, 8);
					}
				}
				if(joy & TRG_RI) {
					if(stage_sel < 100) {
						stage_sel++;
						SoundPlay(0, PhrNo_CURSOR8, 8);
					}
				}
			} else {
				if(joy & TRG_LF) {
					if(color_num > 2) {
						color_num--;
						SoundPlay(0, PhrNo_CURSOR8, 8);
					}
				}
				if(joy & TRG_RI) {
					if(color_num < COLOR_NUM) {
						color_num++;
						SoundPlay(0, PhrNo_CURSOR8, 8);
					}
				}
			}
			if(joy & TRG_AB) {
				MusicPlay(MusNo_COIN);
				StartDelay = 1;
			}
		} else {
			if(++StartDelay >= SEC(2.0)) { break; }
			if((StartDelay >= SEC(0.1)) && (joy & TRG_AB)) { break; }	//キャンセル
		}
	}
}
//*****************************************************************************
//	app_main
//*****************************************************************************
int app_main(int argc, char* argv[]) {
//{{隠しコマンド。Bを押しながら起動すると電池表示を消す。デバッグ時に電池表示を消しやすいようにするためです。
	delay(1);
	if(joy & PAD_B) {
		pceWaveSetMasterAtt(0);
		pcePowerSetReport(PWR_RPTOFF);
	}
//}}隠しコマンド。Bを押しながら起動すると電池表示を消す。デバッグ時に電池表示を消しやすいようにするためです。
	for(;;) {
		SEH_use_shared;
		SEH_try_shared {
			Demo_Run();
		} SEH_catch(SelectException) {
			break;
		} SEH_end
		SEH_try_shared {
			Game_Run();
		} SEH_catch(SelectException) {
			int i;
			for(i = 0; i < SOUND_MAXCH; i++) { sound_stop(i); }
			StopMusic();
		} SEH_end
		stage_sel = stGame.stage;
	}
	return 0;
}
