/* tezuka naoki *//* the long vowel */
#include <stdio.h>
#include <sys/bios.h>
#include <sys/fcntl.h>
#include <stdlib.h>

#define MYSHIP_MAX 1	/* 自機の最大数 */
#define ENEMY_MAX 8		/* 敵機の最大数 */
#define BULLET_MAX 8	/* 敵弾の最大数 */

/* スプライト番号 */
#define SPN_START 0
#define SPN_MYSHIP (SPN_START)
#define SPN_ENEMY (SPN_MYSHIP + MYSHIP_MAX)
#define SPN_BULLET (SPN_ENEMY + ENEMY_MAX)

/* スプライトの最大使用数 */
#define SP_MAX (MYSHIP_MAX + ENEMY_MAX + BULLET_MAX)

/* キャラクタ番号 */
#define CHN_MYSHIP 0
#define CHN_ENEMY 1
#define CHN_BULLET 2

/* 当たり判定ピクセル数 */
#define HIT_JUDGMENT_PIX 5

/* キャラクタ単位の一辺のピクセル数 */
#define ONE_CHR_PIX 8

/* メッセージ用 */
#define SENTENCE 16
#define LCD_CHR_WIDTH (LCD_PIXEL_WIDTH / 8)

/* ミス出発率 ミス発射率 */
#define JAM 20

/* ゲームモード */
typedef enum{
	GAME_END,
	GAME_AGAIN,
} GameMode;

int hi_score = 0;			/* ハイスコア */

int score = 0;				/* 得点 */
int myship_x = 100;			/* 自機座標 */
int myship_y = 50;
int enemy_x[ENEMY_MAX];		/* 敵機座標 */
int enemy_y[ENEMY_MAX];
int bullet_x[BULLET_MAX];	/* 敵弾座標 */
int bullet_y[BULLET_MAX];
int bullet_dx[BULLET_MAX];	/* 敵弾移動量 */
int bullet_dy[BULLET_MAX];

int saved_score = 0;				/* 得点 */
int saved_myship_x = 100;			/* 自機座標 */
int saved_myship_y = 50;
int saved_enemy_x[ENEMY_MAX];		/* 敵機座標 */
int saved_enemy_y[ENEMY_MAX];
int saved_bullet_x[BULLET_MAX];		/* 敵弾座標 */
int saved_bullet_y[BULLET_MAX];
int saved_bullet_dx[BULLET_MAX];	/* 敵弾移動量 */
int saved_bullet_dy[BULLET_MAX];

BYTE myship_mono[8] = {
	0xc3,0x2c,0x12,0x65,0x85,0x81,0x82,0x7c,
};
BYTE enemy_mono[8] = {
	0x3c,0x42,0xa5,0xa5,0x81,0x99,0x81,0x7e,
};
BYTE bullet_mono[8] = {
	0x3c,0x4a,0xa5,0x93,0xc9,0xa5,0x52,0x3c,
};

char * m[SENTENCE] = {
	"                             ",
	"出発！ブイィィィン！         ",
	"やったね！ 五百点突破！      ",
	"ドラゴンへの道！ 千点突破！  ",
	"無口バーにて！ 二千点突破！  ",
	"がんばったで賞！ 三千点突破！",
	"ヒゲが生えたら！ 四千点突破！",
	"命懸けですな                 ",
	"出っ張らないのが良い所       ",
	"少しくらい分けてくれ         ",
	"集団で来ました               ",
	"ピュンピュン太郎健在         ",
	"飲ませてよ水道水             ",
	"おまえはたいした奴ではない   ",
	"イクラの数の子ですってば     ",
	"極楽浄土に行き大会           "
};

void int_swap(int far *a, int far *b); /* swap */
void init_screen(void); /* スクリーンの初期化 */
int int_abs(int a); /* 絶対値 */
GameMode game_loop(void);

/* swap */
void int_swap(int far *a, int far *b){
	int tmp = 0;
	tmp = *a;*a = *b;*b = tmp;
}

/* abs */
int int_abs(int a){
	if(a < 0) a *= -1;
	return a;
}

void init_screen(){
	sprite_set_range(SPN_START, SP_MAX);			/* 表示するスプライト番号の範囲 */
	display_control(DCM_SCR1 | DCM_SPR);			/* 画面の表示状態 */
	text_set_screen(SCREEN1);						/* テキスト表示用スクリーン */
	text_screen_init();								/* テキスト画面初期化 */
	font_set_monodata(CHN_MYSHIP, 1, myship_mono);	/* モノキャラクタ設定 */
	font_set_monodata(CHN_ENEMY, 1, enemy_mono);
	font_set_monodata(CHN_BULLET, 1, bullet_mono);
}

/* ゲームデータの初期化 */
void game_init(){
	int id;
	sprite_set_char(SPN_MYSHIP, CHN_MYSHIP);			/* 自機のスプライトキャラクタ設定 */
	for(id = 0; id < ENEMY_MAX; id++){
		sprite_set_char(SPN_ENEMY + id, CHN_ENEMY);		/* 敵機のスプライトキャラクタ設定 */
		enemy_x[id] = LCD_PIXEL_WIDTH;					/* 敵機を出発待ち状態にセット */
		sprite_set_location(SPN_ENEMY + id, enemy_x[id], 0);
	}
	for(id = 0; id < BULLET_MAX; id++){
		sprite_set_char(SPN_BULLET + id, CHN_BULLET);	/* 敵弾のスプライトキャラクタ設定 */
		bullet_x[id] = LCD_PIXEL_WIDTH;					/* 敵弾を発射待ち状態にセット */
		sprite_set_location(SPN_BULLET + id, bullet_x[id], 0);
	}
}

/* 敵弾の発射 */
void bullet_fire(int tmp_x, int tmp_y){
	int id;
	for(id = 0; id < BULLET_MAX; id++){
		
		/* 発射待ち状態の弾を発射 */
		if(bullet_x[id] == LCD_PIXEL_WIDTH){
			/* 発射失敗 *//* 敵弾をばらつかせる */
			if(rand() % JAM != 0) break;	/* 1 - 1/JAM */
					
			/* 発射主の座標に位置をセット */
			bullet_x[id] = tmp_x;
			bullet_y[id] = tmp_y;

			/* 弾道 *//* 自機に向かう */
			if(tmp_x > myship_x)
				bullet_dx[id] = -1;
			else
				bullet_dx[id] = 1;
	
			if(tmp_y > myship_y)
				bullet_dy[id] = -1;
			else
				bullet_dy[id] = 1;
			break;
		}
	}
}

/* 敵機移動 */
void enemy_move(){
	int id;
	for(id = 0; id < ENEMY_MAX; id++){
		
		/* 出発している敵機を移動させる *//* 出発待ち状態の敵機は移動しない */
		if(enemy_x[id] < LCD_PIXEL_WIDTH){
			/* 敵機位置移動 */
			enemy_x[id]--;

			/* 敵機表示 */
			sprite_set_location(SPN_ENEMY + id, enemy_x[id], enemy_y[id]);

			/* 画面左端まで行くと、元の右端位置にセット *//* 出発待ち状態へ */
			if(enemy_x[id] <= 0)
				enemy_x[id] = LCD_PIXEL_WIDTH;
			/* 敵弾の発射へ */
			bullet_fire(enemy_x[id], enemy_y[id]);
		}
	}
}

/* 敵機の発生 */
void enemy_bone(){
	int tmp_x, tmp_y;
	int id;
	
	/* 発進位置 */
	tmp_x = LCD_PIXEL_WIDTH - 1;
	tmp_y = rand() % LCD_PIXEL_HEIGHT;

	for(id = 0; id < ENEMY_MAX; id++){
		
		/* 出発待ち状態の機体を発進させる */
		if(enemy_x[id] == LCD_PIXEL_WIDTH){
			/* 出発失敗 *//* 敵機をばらつかせる */
			if(rand() % JAM != 0) break;	/* 1 - 1/JAM */
			
			enemy_x[id] = tmp_x;
			enemy_y[id] = tmp_y;
			break;
		}
	}
}

/* 敵弾移動 */
void bullet_move(){
    int tmp_x,tmp_y;
	int id;
	for(id = 0; id < BULLET_MAX; id++){
		
		/* 発射している敵弾を移動させる *//* 発射待ち状態の敵弾は移動しない */
		if(bullet_x[id] < LCD_PIXEL_WIDTH){
			/* 移動予定座標 */
			tmp_x = bullet_x[id]+bullet_dx[id];
			tmp_y = bullet_y[id]+bullet_dy[id];

			/* 敵弾表示 */
			sprite_set_location(SPN_BULLET + id, tmp_x, tmp_y);

			/* 画面から出ると、元の位置にセット *//* 発射待ち状態へ */
			if((tmp_x <= 0)||(tmp_x >= LCD_PIXEL_WIDTH))
				tmp_x = LCD_PIXEL_WIDTH;
			if((tmp_y <= 0)||(tmp_y >= LCD_PIXEL_HEIGHT))
				tmp_x = LCD_PIXEL_WIDTH;

			/* 敵弾の座標を更新 */
			bullet_x[id] = tmp_x;
			bullet_y[id] = tmp_y;
		}
	}
}

/* データを退避 */
void spot_save(){
	int id;
	
	saved_score = score;
	saved_myship_x = myship_x;
	saved_myship_y = myship_y;
	for(id = 0; id < ENEMY_MAX; id++){
		saved_enemy_x[id] = enemy_x[id];
		saved_enemy_y[id] = enemy_y[id];
	}
	for(id = 0; id < BULLET_MAX; id++){
		saved_bullet_x[id] = bullet_x[id];
		saved_bullet_y[id] = bullet_y[id];
		saved_bullet_dx[id] = bullet_dx[id];
		saved_bullet_dy[id] = bullet_dy[id];
	}
}

/* データを復帰 */
void spot_load(){
	int id;
	
	score = saved_score;
	myship_x = saved_myship_x;
	myship_y = saved_myship_y;
	for(id = 0; id < ENEMY_MAX; id++){
		enemy_x[id] = saved_enemy_x[id];
		enemy_y[id] = saved_enemy_y[id];
	}
	for(id = 0; id < BULLET_MAX; id++){
		bullet_x[id] = saved_bullet_x[id];
		bullet_y[id] = saved_bullet_y[id];
		bullet_dx[id] = saved_bullet_dx[id];
		bullet_dy[id] = saved_bullet_dy[id];
	}
}

/* 自機の当たり判定 */
int hit_myship(){
	int id;
	for(id = 0; id < ENEMY_MAX; id++){
		if(int_abs(myship_x - enemy_x[id]) < HIT_JUDGMENT_PIX){
			if(int_abs(myship_y - enemy_y[id]) < HIT_JUDGMENT_PIX) return 1;	/* hit */
		}		
	}
	for(id = 0; id < BULLET_MAX; id++){
		if(int_abs(myship_x - bullet_x[id]) < HIT_JUDGMENT_PIX){
			if(int_abs(myship_y - bullet_y[id]) < HIT_JUDGMENT_PIX) return 1;	/* hit */
		}		
	}
	return 0; /* didn't hit */
}

char *message(int source_score){
	static int msg_counter = 0;	/* メッセージ表示期間 */
	static int msg_wait = 0;	/* メッセージ消灯期間 */
	static int msg_id;			/* メッセージ識別番号 */

	/* 得点に応じてメッセージを決定 */
	if(source_score < 100) return m[1];
	if((source_score > 500) && (source_score < 600)) return m[2];
	if((source_score > 1000) && (source_score < 1100)) return m[3];
	if((source_score > 2000) && (source_score < 2100)) return m[4];
	if((source_score > 3000) && (source_score < 3100)) return m[5];
	if((source_score > 4000) && (source_score < 4100)) return m[6];
	
	if(msg_wait > 0){
		/* 一定の休憩 */
		msg_wait--;
		return m[0];
	}else if(msg_counter > 0){
		/* 一定時間のメッセージ */
		msg_counter--;
		return m[msg_id];
	}else{
		/* 新しいメッセージと表示期間 */
		msg_id = (rand() % 10) + 7; /* 7 〜 15 */
		msg_counter = 200;
		msg_wait = rand() % 500 + 100; /* 100 〜 599 */ 
		return m[0];
	}
}

void myship_move(const int key){
	/* 画面からはみ出ないように自機移動 */
	if((key & KEY_LEFT1) && (myship_x - 1 > 0)) myship_x--;									/*左移動*/
	if((key & KEY_RIGHT1) && (myship_x + ONE_CHR_PIX + 1 < LCD_PIXEL_WIDTH)) myship_x++;	/*右移動*/
	if((key & KEY_UP1) && (myship_y - 1 > 0)) myship_y--;									/*上移動*/
	if((key & KEY_DOWN1) && (myship_y + ONE_CHR_PIX + 1 < LCD_PIXEL_HEIGHT)) myship_y++;	/*下移動*/
		
	/* 自機表示 */
	sprite_set_location(SPN_MYSHIP, myship_x, myship_y);
}

void game_title(){
	text_put_string(4, 8, "-- the long vowel --");
	key_wait();
	text_put_string(4, 8, "                    ");
}

GameMode game_loop(){
	int key;		/*キー入力データ*/
	
	game_title();	/* タイトル画面 */
	game_init();	/* ゲームデータの初期化 */
	
	/* 画面の構成設定 */
	text_put_string(0, 17, "HISC:");
	text_put_numeric(6, 17, 5, 0, hi_score);
	text_put_string(13, 17, "SC:");
	
	for(;;){	
		sys_wait(1);
		
		/* 入力キー受付 */
		key = key_press_check();

		/* >>>>> ゲーム終了 <<<<< */
		if (key & KEY_START) return GAME_END;
		
		myship_move(key);	/* 自機移動 */
		enemy_bone();		/* 敵出現 */
		enemy_move();		/* 敵機移動 */
		bullet_move();		/* 敵弾移動 */
		
		if(key & KEY_B) spot_save();	/* 状態を退避 */
		if(key & KEY_A) spot_load();	/* 状態を復帰 */
		
		/* 加点 */
		score++;
		
		/* 得点表示 */
		text_put_numeric(17, 17, 5, 0, score);
		
		/* メッセージ表示 */
		text_put_string(0, 0, message(score));
		
		/* 自機当たり判定 */
		if(hit_myship()){
			text_put_string(8, 8, "GAME IS OVER");
			key_wait();
			text_put_string(8, 8, "            ");
			if(score > hi_score) hi_score = score;
			score = 0;
			return GAME_AGAIN;/* >>>>> ゲーム終了 <<<<< */
		}
		
		/* pause */
		if(key & KEY_UP2) key_wait(); /* コマ送り機能アリ */
	}
}

int main(int argc, char *argv[])
{
	init_screen();
	srand(sys_get_tick_count());
	while(game_loop() == GAME_AGAIN)
		;
	return 0;
}

