/*        『てろてろろーぱー』       */
/*	Ｐｒｅｓｅｎｔｅｄ　ｂｙ　Ａｙａ */
/*                ２００１．１．３１ */

#include <sys/bios.h>
#include <stdlib.h>
#include "roper.h"
#include "dfly.h"
#include "through.h"	/* 透明色 */

#include "zero.h"
#include "one.h"
#include "two.h"
#include "three.h"
#include "four.h"
#include "five.h"
#include "six.h"
#include "seven.h"
#include "eight.h"
#include "nine.h"



/* 画面サイズ */
/* 縦１８     */
/* 横２８     */

#define		WINDOW_WIDTH	28*8	/* ウィンドウ幅（ドット）*/
#define		WINDOW_HEIGHT	18*8	/* ウィンドウ高（ドット）*/

#define		ROPER_WIDTH		roper_width
#define		ROPER_HEIGHT	roper_height
#define		DFLY_WIDTH		dfly_width
#define		DFLY_HEIGHT		dfly_height
#define		SLIDER_WIDTH	slider_width
#define		SLIDER_HEIGHT	slider_height


#define		MAX_ROPER_COUNT	16		/* ローパー数       */
#define		MAX_ROPER_FLAME	3		/* ローパーフレーム */

#define		PHASE_GAME 0			/* ゲーム中   */
#define		PHASE_END 1				/* ゲーム終了 */




/* RECT 構造体 */
typedef struct tag_MYRECT{
	double left;
	double top;
	double right;
	double bottom;
} MYRECT;


typedef struct tag_ROPER {
	double x;						/* x 座標         */
	double y;						/* y 座標         */
	double dx;						/* x 移動量       */
	double dy;						/* y 移動量       */
	MYRECT hit;						/* 当たり判定     */
	int anime[MAX_ROPER_FLAME];		/* アニメＮｏ     */
	int status;						/* ローパーの状態 */
} EROPER;


typedef struct tag_DFLY{
	double x;						/* x 座標       */
	double y;						/* y 座標       */
	double dx;						/* x 移動量     */
	double dy;						/* y移動量      */
	MYRECT hit;						/* 当たり判定   */
	int status;						/* とんぼの状態 */
} EDFLY;


/* ローパーの状態 */
enum STATUS
{
	WAITING,	/* 画面外で待機中（停止中）*/
	MOVING,		/* 画面を横断中　（移動中）*/
	CATCHING,	/* 捕獲中                  */
} condition;


int PHASE;									/* フェイズ管理変数       */
EROPER	ROPER[MAX_ROPER_COUNT];				/* ローパー               */
int ROPER_DEFAULT_XPOS[MAX_ROPER_COUNT];	/* ローパーのＸ座標格納庫 */
EDFLY	DFLY;								/* とんぼ                 */
int		SCORE;								/* 点数（捕獲ローパー数） */
int		LIMIT;								/* 残り時間               */

/**********************************************
 ２つの矩形が重なってるか計算します。
 引数　：*rect1 - RECT構造体１
 　　　：*rect2 - RECT構造体２
 戻り値：0 - 重なってない
 　　　：1 - 重なっている（境界線含む）
 備考　：結果を RECT構造体 へのポインタで渡します。
**********************************************/
int intersect_rect(MYRECT *rect, MYRECT *rect1, MYRECT *rect2)
{
	if(rect1->left > rect2->left){
		rect->left = rect1->left;
	}
	else{
		rect->left = rect2->left;
	}

	if(rect1->top > rect2->top){
		rect->top = rect1->top;
	}
	else{
		rect->top = rect2->top;
	}

	if(rect1->right < rect2->right){
		rect->right = rect1->right;
	}
	else{
		rect->right = rect2->right;
	}

	if(rect1->bottom < rect2->bottom){
		rect->bottom = rect1->bottom;
	}
	else{
		rect->bottom = rect2->bottom;
	}

	/* ２つの矩形が重なってるか計算します */
	if(rect->left <= rect->right && rect->top <= rect->bottom){ /* 重なってるとき */
		return 1;
	}
	else{ /* 重なってないとき */
		rect->left = 0;
		rect->top = 0;
		rect->right = 0;
		rect->bottom = 0;
		
		return 0;
	}
}




/*********************************************
 乱数を生成して返します。
 引数　：minsize, maxsize
 戻り値：int value
 備考　：minsize〜maxsize の値を返します。
**********************************************/
int make_random(int minsize, int maxsize)
{
	int value; // 生成する乱数。

	value = (rand() % ((maxsize-minsize)+1)) + minsize;

	return value;
}






/*********************************************
 画面を書き換えます。
 引数　：
 戻り値：
 備考　：
**********************************************/
void make_display()
{

	int i;
	int j;
	int k;
	int tmpscore;
	int tmptime;

	tmpscore = 0;

	/* ローパー描画 */
	for(k = 0; k < MAX_ROPER_COUNT; k++){
		for(j = 0; j < ROPER_HEIGHT; j++){
			for(i = 0; i < ROPER_WIDTH; i++){
				sprite_set_location((k*4)+(i+j*ROPER_WIDTH)+20, ROPER[k].x+i*8, ROPER[k].y+j*8);
			}
		}
	}

	/* とんぼ描画 */
	for(i = 0; i < 5; i++){
		sprite_set_location(15 + i, DFLY.x , DFLY.y+(i * 8) );
	}


	/* 点数描画 */
	/* １の位 */
	tmpscore = (int)(SCORE % 10); 
	for(i = 0; i < 10; i++){
		if(i == tmpscore){
			sprite_set_char(11, (4<<9) | CFM_SPR_UPPER | i + 10);
		}
	}


	/* １０の位 */
	tmpscore = (int)(SCORE /10);
	for(i = 0; i < 10; i++){
		if(i == tmpscore){
			sprite_set_char(10, (4<<9) | CFM_SPR_UPPER | i + 10);
		}
	}


	/* 残り時間描画 */
	tmptime = (int)(LIMIT / 100); 
	for(i = 0; i < 10; i++){
		if(i == tmptime){
			sprite_set_char(9, (4<<9) | CFM_SPR_UPPER | i + 10);
		}

	}

	LIMIT = LIMIT - 2;

}



/**********************************************
 ローパーを待機状態でスタンバイさせます。
 引数　：i（ローパーのインデックス）
 戻り値：なし
 備考　：画面からはみ出たローパーに対して働く関数です
**********************************************/
void waiting_roper(int i)
{
	int temp;
	int speed;
	int sign;	/* プラス、マイナスを格納します */

/* ローパーのｘ座標はまだ変更しません。*/


	temp = make_random(0, 1);
	if(0 == temp){ /* 上から下に移動させます */
		sign = 1;
		ROPER[i].y = -ROPER_HEIGHT * 8;
	}
	else if(1 == temp){ /* 下から上に移動させます */
		sign = -1;
		ROPER[i].y = WINDOW_HEIGHT; 
	}

	/* x座標 をデフォに戻します */
	ROPER[i].x = ROPER_DEFAULT_XPOS[i];

	speed = make_random(1, 4);
	ROPER[i].dy = speed * sign;

	ROPER[i].status = WAITING;

}




/**********************************************
 待機中のローパーが動き出すか決めます。
 引数　：i（ローパーのインデックス）
 戻り値：なし
 備考　：
**********************************************/
void start_roper(int i)
{

	int value;

	value = make_random(1, 100);

	if(3 > value){ /* ２％の確立で動き出します */
		ROPER[i].status = MOVING;
	}

}


/**********************************************
 とんぼとローパーが重なってるか調べます。
 引数　：
 戻り値：
 備考　：
**********************************************/
void hit_check()
{
	int i;
	int result;
	MYRECT rect;

	for(i= 0; i < MAX_ROPER_COUNT; i++){
		result = intersect_rect(&rect, &ROPER[i].hit, &DFLY.hit);

		if(1 == result){
			ROPER[i].dx = DFLY.dx;
			ROPER[i].status = CATCHING;

			/* ローパーの当たり判定を画面外に追いやります */
			ROPER[i].hit.left = -40;
			ROPER[i].hit.top = -40;
			ROPER[i].hit.right = -40;
			ROPER[i].hit.bottom = -40;

		}
	}

}





/**********************************************
 とんぼを動かします。
 引数　：
 戻り値：
 備考　：
**********************************************/
void move_dfly()
{
	int i;
	int key;

	if(DFLY.status == WAITING){
		key = key_press_check();
		switch(key){
		case KEY_Y1:
			DFLY.y = DFLY.y - DFLY.dy;
			break;

		case KEY_Y3:
			DFLY.y = DFLY.y + DFLY.dy;
			break;

		case KEY_X3:
			DFLY.status = MOVING;
			break;

		default:
			break;
		}

		/* とんぼが画面の上下からはみ出したとき */
		if(DFLY.y < 0){
			DFLY.y = 0;
		}
		else if(DFLY.y > WINDOW_HEIGHT - DFLY_HEIGHT * 8){
			DFLY.y = WINDOW_HEIGHT - DFLY_HEIGHT * 8;
		}


	}
	else if(DFLY.status == MOVING){
		DFLY.x = DFLY.x + DFLY.dx;
	}

	/* 当たり判定セット */
	if(DFLY.dx > 0){ /* とんぼが上向きのとき */
		/* 当たり判定セット */
		DFLY.hit.left = DFLY.x + 1;
		DFLY.hit.top = DFLY.y;
		DFLY.hit.right = DFLY.x + 1;
		DFLY.hit.bottom = DFLY.y + 39;
	}
	else if(DFLY.dx < 0){ /* とんぼが下向きのとき */
		/* 当たり判定セット */
		DFLY.hit.left = DFLY.x + 3;
		DFLY.hit.top = DFLY.y;
		DFLY.hit.right = DFLY.x + 3;
		DFLY.hit.bottom = DFLY.y + 39;
	}


	/* とんぼが画面右端まで達したとき */
	if(DFLY.x > WINDOW_WIDTH - (DFLY_WIDTH + ROPER_WIDTH) * 8 + 8){
		/* 左向きとんぼ（とんぼ２）セット */
		for(i = 0; i < DFLY_WIDTH * DFLY_HEIGHT; i++){
			sprite_set_char(15+ i, (4<<9) | CFM_SPR_UPPER | 5 + i);
		}

		DFLY.x = WINDOW_WIDTH - (DFLY_WIDTH + ROPER_WIDTH) * 8 + 8;

		DFLY.dx = -DFLY.dx;
		DFLY.status = WAITING;
	}
	/* とんぼが画面左端まで達したとき */
	else if(DFLY.x < 0){
		/* 右向きとんぼ（とんぼ１）セット */
		for(i = 0; i < 5; i++){
			sprite_set_char(15 + i, (4<<9) | CFM_SPR_UPPER | 5 + i);
		}


		DFLY.x = 0;

		DFLY.dx = -DFLY.dx;
		DFLY.status = WAITING;
	}




}




/**********************************************
 ローパーを動かします。
 引数　：
 戻り値：
 備考　：
**********************************************/
void move_roper()
{
	int i;


	for(i = 0; i < MAX_ROPER_COUNT; i++){
		/* 待機状態のローパーを動かすか決めます */
		if(ROPER[i].status == WAITING){
			start_roper(i);
		}

		if(ROPER[i].status == MOVING){ /* ローパーのステイタスが『MOVING』ならローパーを動かします */
			ROPER[i].y = ROPER[i].y + ROPER[i].dy;

			/* ローパーの当たり判定を設定します */
			ROPER[i].hit.left = ROPER[i].x + 3;
			ROPER[i].hit.top = ROPER[i].y ;
			ROPER[i].hit.right = ROPER[i].x + 6;
			ROPER[i].hit.bottom = ROPER[i].y + 13;
		}
		else if(ROPER[i].status == CATCHING){
			/* 画面左右端に達しているとき */
			if(ROPER[i].x > (WINDOW_WIDTH - ROPER_WIDTH*8) || ROPER[i].x < 0){
				ROPER[i].dx = 0;
				ROPER[i].y = ROPER[i].y - 14;
			}
			else{
				ROPER[i].x = ROPER[i].x + ROPER[i].dx;
			}
		}


		/* 待機中じゃないローパーに対しての処理 */
		if(ROPER[i].status != WAITING){
			/* 横移動中のローパーが画面から外に出たとき */
			if(ROPER[i].y > WINDOW_HEIGHT || ROPER[i].y < -ROPER_HEIGHT * 8){
				if(ROPER[i].status == CATCHING){
					SCORE = SCORE + 1;
				}
				waiting_roper(i);
			}
		}

	}


}



/**********************************************
 ゲームの初期化をします。
 引数　：
 戻り値：
 備考　：
**********************************************/
void init_game()
{
	int i;
	double speed;

	LIMIT = 1000;
	SCORE = 0;


	/* ローパーの基本 x座標 を決めておきます */
	for(i = 0; i < MAX_ROPER_COUNT; i++){
		ROPER_DEFAULT_XPOS[i] = 40 + i*8;
	}

	/* ローパーのプロパティをセットします */
	for(i = 0; i < MAX_ROPER_COUNT; i++){
		speed = make_random(1, 5);
		ROPER[i].x = ROPER_DEFAULT_XPOS[i];

		/* ローパーの初期位置（左右、ROPER[i].y）を決めます */
		waiting_roper(i);

		ROPER[i].dx = 0;
		ROPER[i].dy = speed;
	}


	/* とんぼ */
		/* 初期座標セット */
		DFLY.x = -20;
		DFLY.y = (WINDOW_HEIGHT - DFLY_HEIGHT * 8) / 2;
		DFLY.dx = 4;
		DFLY.dy = 5;

		/* 当たり判定セット */
		DFLY.hit.left = DFLY.x + 3;
		DFLY.hit.top = DFLY.y;
		DFLY.hit.right = DFLY.x + 3;
		DFLY.hit.bottom = DFLY.y + 39;

		/* 状態セット */
		DFLY.status = WAITING;


}







/**********************************************
 メインループ。
 引数　：
 戻り値：
 備考　：
**********************************************/
void main()
{


	int i;

	text_screen_init();
	display_control(DCM_SPR);

	/* プロセスIDを種に乱数を初期化 */
	srand(sys_get_tick_count() & 0x7fff);

	/* キャラクタフォント１〜４にローパーをセット */
	font_set_colordata( 1, 4, bmp_roper );


	/* キャラクタフォント５〜９にとんぼをセット */
	font_set_colordata(5, 9, bmp_dfly);


	/* キャラクタフォント１０〜１９に数字をセット */
	font_set_colordata(10, 1, bmp_zero);
	font_set_colordata(11, 1, bmp_one);
	font_set_colordata(12, 1, bmp_two);
	font_set_colordata(13, 1, bmp_three);
	font_set_colordata(14, 1, bmp_four);
	font_set_colordata(15, 1, bmp_five);
	font_set_colordata(16, 1, bmp_six);
	font_set_colordata(17, 1, bmp_seven);
	font_set_colordata(18, 1, bmp_eight);
	font_set_colordata(19, 1, bmp_nine);



	init_game();


	/* 残り時間セット */
		sprite_set_char(9, (4<<9) | 12);  /* 残り時間 */
		sprite_set_location(9, WINDOW_WIDTH - 16, WINDOW_HEIGHT - 16);

	/* 点数セット */
		sprite_set_char(10, (4<<9) | 11); /* 点数１０の位 */
		sprite_set_char(11, (4<<9) | 12); /* 点数１の位 */
		sprite_set_location(10, WINDOW_WIDTH - 28, WINDOW_HEIGHT - 24);
		sprite_set_location(11, WINDOW_WIDTH - 28, WINDOW_HEIGHT - 16);




	/* とんぼ */
		/* とんぼセット */
		sprite_set_char(15, (4<<9) | CFM_SPR_UPPER | 5);
		sprite_set_char(16, (4<<9) | CFM_SPR_UPPER | 6);
		sprite_set_char(17, (4<<9) | CFM_SPR_UPPER | 7);
		sprite_set_char(18, (4<<9) | CFM_SPR_UPPER | 8);
		sprite_set_char(19, (4<<9) | CFM_SPR_UPPER | 9);



	sprite_set_range(0, 128);





	/* ローパー１*/
	for(i = 20; i < 24; i++){
		sprite_set_char(i, (4<<9) | (i+1)-20);
	}

	/*  ローパー２ */
	for(i = 24; i < 28; i++){
		sprite_set_char(i, (4<<9) | (i+1)-4-20);
	}

	/*  ローパー３ */
	for(i = 28; i < 32; i++){
		sprite_set_char(i, (4<<9) | (i+1)-8-20);
	}

	/*  ローパー４ */
	for(i = 32; i < 36; i++){
		sprite_set_char(i, (4<<9) | (i+1)-12-20);
	}

	/*  ローパー５ */
	for(i = 36; i < 40; i++){
		sprite_set_char(i, (4<<9) | (i+1)-16-20);
	}

	/*  ローパー６ */
	for(i = 40; i < 44; i++){
		sprite_set_char(i, (4<<9) | (i+1)-20-20);
	}

	/*  ローパー７ */
	for(i = 44; i < 48; i++){
		sprite_set_char(i, (4<<9) | (i+1)-24-20);
	}

	/*  ローパー８ */
	for(i = 48; i < 52; i++){
		sprite_set_char(i, (4<<9) | (i+1)-28-20);
	}

	/*  ローパー９ */
	for(i = 52; i < 56; i++){
		sprite_set_char(i, (4<<9) | (i+1)-32-20);
	}

	/*  ローパー１０ */
	for(i = 56; i < 60; i++){
		sprite_set_char(i, (4<<9) | (i+1)-36-20);
	}

	/*  ローパー１１ */
	for(i = 60; i < 64; i++){
		sprite_set_char(i, (4<<9) | (i+1)-40-20);
	}

	/*  ローパー１２ */
	for(i = 64; i < 68; i++){
		sprite_set_char(i, (4<<9) | (i+1)-44-20);
	}

	/*  ローパー１３ */
	for(i = 68; i < 72; i++){
		sprite_set_char(i, (4<<9) | (i+1)-48-20);
	}

	/*  ローパー１４ */
	for(i = 72; i < 76; i++){
		sprite_set_char(i, (4<<9) | (i+1)-52-20);
	}

	/*  ローパー１５ */
	for(i = 76; i < 80; i++){
		sprite_set_char(i, (4<<9) | (i+1)-56-20);
	}

	/*  ローパー１６ */
	for(i = 80; i < 84; i++){
		sprite_set_char(i, (4<<9) | (i+1)-60-20);
	}




	PHASE = PHASE_GAME;
	


	/* キーが押されるまで待ちます。*/
	while ( (key_press_check()&0x7fe) ) ;


	while(PHASE != PHASE_END){
		switch(PHASE){
		case PHASE_GAME:			/* ゲーム中 */

			for(;;){
				move_dfly();
				hit_check();
				move_roper();
				make_display();


				/* 時間切れ */
				if(LIMIT < 0){
					sys_wait(150);
					switch(key_wait()){
					case KEY_START:
						PHASE = PHASE_END;
						break;
					default:
						init_game();
						break;
					}

				}



				if((key_press_check()&0x7fe) == KEY_START ){
					PHASE = PHASE_END;
					break;
				}
			}
			break;

		
		case PHASE_END:				/* ゲーム終了 */
			break;

		default:					/* ここには流れてこない、エラー処理とかしておく。*/
			PHASE = PHASE_END;
			break;
			

		}
	}



}

