/*-------------------------
 *
 *	デジベーダー
 *
 *		Programed by H.Fujii
 *
------------------------ */

#ifdef _DUMMY_TEXT_
#include <stdio.h>
#endif

#ifdef LSI_C
#pragma noregalo
#endif

#include <sys/bios.h>
#include <sys/process.h>
#include <stdlib.h>

#define TARGET_X		 0
#define TARGET_Y		 8


#ifndef BIOS_INLINE
#ifdef LSI_C_WW
#pragma noregalo
#endif /* LSI_C_WW */
#endif /* ! BIOS_INLINE */

#include "char24.h"




unsigned short degi_scr[0x00c];
int invader[9];
int apper_vader;
int apper_point;
int apper_timer;

int death_vader;

int apper_ufo;
int ufo_counter;

int score;
int HIscore = 0;

int GAME_MODE;

int game_level = 0;
int apper_set[10] = {75, 70, 65, 60, 55, 50, 45, 40, 35, 30};

int zanki;
int target;


/* --------------------------------
	スクリーンデータのセット
-------------------------------- */

void scr_set(int c) {
	int wx, wy;
	for (wy = 0 ; wy < 4 ; wy++){
		for (wx = 0 ; wx < 3 ; wx++){
			degi_scr[wx + (wy * 3)] = c + wx + (wy * 3);
		}
	}
}



/* ---------------------------------
	インベーダー初期化
--------------------------------- */

void invader_init(void){
	int i;

	for (i = 0 ; i < 9 ; i++){
		invader[i] = 0x0b;				/* 空の７セグセット */
	}

	game_level = 0;
	apper_vader = 0;
	apper_point = 0;
	apper_timer = 0;
	death_vader = 0;
	apper_ufo = 0;
	ufo_counter = 0;
	zanki = 3;
	target = 1;
	score = 0;
}



/* ---------------------------------
	Xのn乗を求める
--------------------------------- */

int pow(int x, int n){
	int i;
	int ans = 1;

	if (n < 1) return (1);

	for (i = 1 ; i < n + 1 ; i++){
		ans *=x;
	}

	return (ans);
}



/* --------------------------------------------
	次のインベーダーを出現させる

		２０匹セットしていたら止める

-------------------------------------------- */

void new_invader_set(void){

	/* インベーダーが２０匹出現していたら空白のセット */

	if (apper_vader == 20){
		invader[0] = 11;				/* 空白７セグ */
	}
	else {

		/* UFO switch ON なら UFOをセット */

		if (apper_ufo == 1){
			invader[0] = 10;				/* UFO set */
			apper_ufo = 0;					/* UFO switch OFF */
		}
		else {
			invader[0] = rand() % 9 + 1;
		}
		apper_vader ++;
	}
}



/* --------------------------------
	インベーダーを表示します
-------------------------------- */

void invader_disp(void){
	int i;

	for (i = 0 ; i < 7 ; i++){
		scr_set(0x04 + (0x0c * invader[i]));
		screen_set_char( 0, (8 - i) * 3, 0, 3, 4, degi_scr);
	}
}



/* --------------------------------
	残機数表示
-------------------------------- */

void zanki_disp(void){

	if (zanki == 0) return;							/* 残機が０の時は表示しない（ゲームオーバー） */

	scr_set(0x88 + (zanki - 1) * 0x0c);
	screen_set_char( 0, 3, 0, 3, 4, degi_scr);		/* 残機数表示 */
}



/* --------------------------------
	インベーダー占領成功
-------------------------------- */

void invader_win1(void){


	zanki--;

	if (zanki == 0){
		GAME_MODE = 2;					/* GAME OVER 処理に移行 */
	}
	else{
		GAME_MODE = 4;					/* 占領処理に移行 */
	}
}



/* --------------------------------
	インベーダー占領成功 点滅デモ
-------------------------------- */

void invader_win2(int timer){

	int i;

	if ((timer & 0x10) == 0){
		for (i = 0 ; i < 8 ; i++){
			scr_set(0x04 + (0x0c * invader[i]));
			screen_set_char( 0, (8 - i) * 3, 0, 3, 4, degi_scr);
		}
	}
	else {
		for (i = 0 ; i < 8 ; i++){
			scr_set(0x04 + (0x0c * 11));
			screen_set_char( 0, (8 - i) * 3, 0, 3, 4, degi_scr);
		}
	}
}




/* --------------------------------
	インベーダーを動かします
-------------------------------- */

void invader_move(void){

	int i;

	apper_timer++;

	if (apper_timer > apper_set[game_level]){
		apper_timer = 0;
		apper_point++;

		for (i = 6 ; i >= 0 ; i--){
			invader[i + 1] = invader[i];
		}

		new_invader_set();						/* 新人をセット */

		if (apper_point > 7) invader_win1();		/* インベーダー占領成功 */
	}
}



/* -----------------------------------------------
	スコアーを表示
------------------------------------------------*/

void disp_score(int sc){

	int w0, w1, i, j = 0;

	w0 = sc;


	for (i = 7 ; i >= 0 ; i--){
		w1 = w0 / pow(10, i);

		if((w1 == 0) && (j == 0) && (i != 0)){
			scr_set(0x04 + (0x0c * 11));
			screen_set_char( 0, (8 - i) * 3, 6, 3, 4, degi_scr);
		}
		else {
			j = 1;
			scr_set(0x04 + (0x0c * w1));
			screen_set_char( 0, (8 - i) * 3, 6, 3, 4, degi_scr);
		}

		w0 = w0 % pow(10, i);
	}
}



/* --------------------------------------------------------------------------------
	インベーダーを撃ちます

	invader[6],invader[5],.....,invader[0]


	apper_point		9876543210			インベーダ(invader[6])の先頭位置
	DISP Pos		012345678			７セグの表示位置
	実際の表示		8-1234567			ゲーム画面

-------------------------------------------------------------------------------- */

void shot_invader(int target){

	int i, j;

	for (i = apper_point ; i > 0 ; i--){

		if (invader[i - 1] == target){

			death_vader ++;						/* 撃ち落したインベーダーの数 */

			/* --------------------------------------
				やられたインベーダーをずらして消す
			-------------------------------------- */
			for (j = i ; j < 7 ; j++){
				invader[j - 1] = invader[j];
			}

			score += (i * 10);					/* 得点を加算 */

			if (target == 10) score += 300;		/* UFOは300点増し */


			/* インベーダの種類を足し算して下１桁が０ならUFOを出現 */

			ufo_counter += target;

			if ((ufo_counter % 10 == 0) && (target != 10)){
				apper_ufo = 1;					/* UFO switch ON */
			}

			invader[6] = 11;				/* 空白７セグ */

			apper_point--;
			apper_timer = 0;

			if (death_vader == 20){						/* 撃ち落したインベーダーの数 */
				GAME_MODE = 6;							/* STAGE CLEAR 処理に移行 */
				apper_point = 0;
				apper_timer = 0;
				apper_vader = 0;
				death_vader = 0;
				for (j = 0 ; j < 9 ; j++){
					invader[j] = 0x0b;				/* 空の７セグセット */
				}
			}

			break;
		}
	}
}



/* --------------------------------
	ゲームのメイン
-------------------------------- */

void game_main(void){

	scr_set(0x04 + (0x0c * target));
	screen_set_char( 0, 0, 0, 3, 4, degi_scr);			/* ターゲットセット */

	switch (key_hit_check()) {

		case KEY_UP2:							/* GAME EXIT */
			GAME_MODE = 9;
			break;

		case KEY_START:							/* PAUSE */
			GAME_MODE = 10;
			break;

		case KEY_RIGHT1:						/* TARGET MOVE */
			target++;
			if (target > 10) target = 1;
			break;

		case KEY_LEFT1:
			target--;
			if (target < 1) target = 10;
			break;

		case KEY_A:								/* SHOT */
		case KEY_B:
			shot_invader(target);
			break;


		default:
			break;
	}

	invader_move();

	zanki_disp();						/* 残機数表示 */

	invader_disp();						/* 書き直す */

	disp_score(score);					/* スコアを書く */
}



/* --------------------------------
	ゲームタイトル
-------------------------------- */

void game_open(int timer){


	if ((timer & 0x10) == 0){
		text_put_string(0, 12, "         GAME START");
		text_put_string(0, 14, "       PRESS [START]");
	}
	else {
		text_put_string(0, 12, "                   ");
		text_put_string(0, 14, "                    ");
	}



	switch (key_hit_check()) {
		case KEY_START:
			GAME_MODE = 1;
			invader_init();

			text_put_string(0, 12, "                   ");
			text_put_string(0, 14, "                    ");
			text_put_string(0, 5, "SCORE:   ");

			break;

		case KEY_UP2:
			GAME_MODE = 9;
			break;
	}
}



/* --------------------------------
	ゲームポーズ
-------------------------------- */

void game_pause(int timer){


	if ((timer & 0x10) == 0){
		text_put_string(0, 12, "           PAUSE");
		text_put_string(0, 14, "       PRESS [START]");
	}
	else {
		text_put_string(0, 12, "                   ");
		text_put_string(0, 14, "                    ");
	}


	switch (key_hit_check()) {
		case KEY_START:							/* PAUSE 解除 */
			GAME_MODE = 1;
			text_put_string(0, 12, "                   ");
			text_put_string(0, 14, "                    ");
			text_put_string(0, 5, "SCORE:   ");
			break;

		case KEY_UP2:							/* GAME EXIT */
			GAME_MODE = 9;
			break;
	}
}



/* --------------------------------
	ゲームオーバー
-------------------------------- */

void game_over(int timer){
/*
">------------<>------------<"
"0123456789012345678901234567"
*/
	if ((timer & 0x10) == 0){
		text_put_string(0, 12, "         GAME OVER ");
		text_put_string(0, 14, "       PRESS [START]");
	}
	else {
		text_put_string(0, 12, "                   ");
		text_put_string(0, 14, "                    ");
	}

	invader_win2(timer);			/* インベーダーの点滅 */

	switch (key_hit_check()) {
		case KEY_START:
			GAME_MODE = 3;
			break;

		case KEY_UP2:
			GAME_MODE = 9;
			break;
	}
}



/* --------------------------------------
	main program
-------------------------------------- */

void main(int argc, char *argv[]) {

	int loop = 1;
	int timer = 0;
	int i;

	srand(0);										/* 乱数の種セット */

	display_control(DCM_SCR1);

	screen_set_scroll(0, 0, 0);						/* スクリーン1のスクロールを(0,0)に設定 */
	screen_set_scroll(1, 0, 0);						/* スクリーン2のスクロールを(0,0)に設定 */

	/*	0x00(薄い) << 濃さ >> 0x0f(濃い) */

	lcd_set_color(0x6420, 0xeca8);					/* 基本の８色を設定 */

	palette_set_color(0, 0x7420);					/* パレット０にカラーセット */

	text_set_mode(TEXT_MODE_ANK);					/* テキスト表示モードをTEXT_MODE_ANK に設定 */
	text_screen_init();
	text_set_screen(0);								/* スクリーン2 をテキストエリアに */

	font_set_colordata(0, 0xb8, obj_data);			/*キャラ 0 〜 0xb7 を設定 */

	screen_fill_char(0, 0, 0, 32, 32, 0);			/* スクリーン1をキャラ0で埋める */


	scr_set(0x88);
	for ( i = 0 ; i < 9 ; i++){
		screen_set_char( 0, i * 3, 0, 3, 4, degi_scr);		/* 空デジタルセット */
		screen_set_char( 0, i * 3, 6, 3, 4, degi_scr);		/* 空デジタルセット */
	}

	text_put_string(0, 5, "Hi-SCORE:");
	disp_score(HIscore);

	GAME_MODE = 0;

	text_put_string(0, 17, "  Y1 KEY : Exit form GAME");


	/* --------------------------------
		ゲームのメインループ
	-------------------------------- */

	while (loop) {

		switch (GAME_MODE){

			/* DEMO */

			case 0:
				game_open(timer);
				timer++;
				break;


			/* GAME PLAY */

			case 1:
				game_main();
				break;


			/* GAME OVER */

			case 2:
				game_over(timer);
				timer++;
				break;

			case 3:
				GAME_MODE = 0;
				scr_set(0x88);
				for ( i = 0 ; i < 9 ; i++){
					screen_set_char( 0, i * 3, 0, 3, 4, degi_scr);		/* 空デジタルセット */
				}

				if (score > HIscore) HIscore = score;
				text_put_string(0, 5, "Hi-SCORE");
				disp_score(HIscore);
				break;


			/* 占領 */

			case 4:
				timer = 0;
				GAME_MODE ++;

			case 5:
				timer++;
				invader_win2(timer);

				if (timer > 300){
					apper_point = 0;
					for (i = 0 ; i < 9 ; i++){
						invader[i] = 0x0b;				/* 空の７セグセット */
					}
					apper_vader = death_vader;
					GAME_MODE = 1;
				}

				break;


			/* クリア */

			case 6:
				timer = 0;
				GAME_MODE ++;
				game_level = (game_level < 9)? game_level + 1 : 9;			/* レベルアップ */

			case 7:
				timer++;

				if ((timer & 0x10) == 0){
					disp_score(score);
				}
				else {
					scr_set(0x88);
					for ( i = 0 ; i < 9 ; i++){
						screen_set_char( 0, i * 3, 6, 3, 4, degi_scr);		/* 空デジタルセット */
					}
				}

				if (timer > 300) GAME_MODE = 1;

				break;


			/* Exit */

			case 9:
				loop = 0;
				break;


			/* PAUSE */

			case 10:
				timer = 0;
				GAME_MODE ++;

			case 11:
				timer++;
				game_pause(timer);
				break;
		}
		sys_wait(0);
	}

}



