/* おきらくだいさくせん♪ for WonderSwan */

#include <stdio.h>
#include <sys/bios.h>

#define FONT_SPACE 0
#define FONT_MY (FONT_SPACE + 1)
#define FONT_TAMA (FONT_MY + 8)
#define FONT_FREE (FONT_TAMA + 1)

#define MOVE_WAIT_DEF 4000		/* 移動時のウェイト */
#define ROTATE_WAIT_DEF 20		/* 回転時のウェイト */
#define LAST_STAGE 10			/* 最終面 */


BYTE space[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

unsigned short tama[] = {
	0x0000, 0x0000, 0x0303, 0x0E0D, 0x1817, 0x101F, 0x302F, 0x203F
};

unsigned short my_char[] = {
	0x0000,0x0101,0x0303,0x0707,0x0f0f,0x1f1f,0x3f3f,0x0101,
	0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7f7f,
	0x0000,0x0000,0x4040,0x6060,0x7070,0x7878,0x7c7c,0xfefe,
	0x0000,0x0000,0x0303,0x0101,0x0000,0x0000,0x0000,0x0101,
	0x0000,0x0000,0xfcfc,0xfcfc,0xfcfc,0x7c7c,0xfcfc,0xdcdc,
	0x0303,0x0707,0x0e0e,0x1c1c,0x3838,0x1010,0x0000,0x0000,
	0x8c8c,0x0404,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
};

unsigned short sprite_data[] = {
	0x2800,0x6800,0x2801,0x6801,0x2804,0x2805,0x2806,0x2807,
	0x2802,0x2803,0xa802,0xa803,0xa806,0xa807,0xa804,0xa805,
	0xa801,0xe801,0xa800,0xe800,0xe807,0xe806,0xe805,0xe804,
	0x6803,0x6802,0xe803,0xe802,0x6805,0x6804,0x6807,0x6806
};

unsigned short stage_data[] = {
	0x000,0x0f0,0x108,0x110,0x120,0x140,0x080,0x000,3,6,2,
	0x000,0x000,0x118,0x220,0x040,0x208,0x208,0x000,4,4,4,
	0x000,0x1f8,0x008,0x000,0x000,0x040,0x078,0x000,1,1,2,
	0x7f0,0x638,0x554,0x492,0x554,0x638,0x3f0,0x000,1,6,7,
	0x000,0x150,0x000,0x150,0x000,0x150,0x000,0x000,9,1,3,
	0x1c8,0x228,0x228,0x248,0x088,0x088,0x000,0x088,2,5,6,
	0x000,0x040,0x040,0x040,0x3b8,0x040,0x040,0x040,5,4,3,
	0x000,0x0f0,0x090,0x390,0x270,0x240,0x3c0,0x000,3,5,7,
	0x040,0x248,0x150,0x0e0,0x0e0,0x150,0x248,0x040,1,2,7,
	0x000,0x392,0x454,0x458,0x458,0x454,0x392,0x000,3,3,7,
	0x820,0x100,0x408,0x082,0x210,0x844,0x100,0x008,11,6,10,
};

unsigned char wave_data[] = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

typedef struct {
	int x;
	int y;
	int muki;
	int stage;
	int brake;
	int rest;
	int miss;
	int data[12][8];
	unsigned short move_wait;
	unsigned short rotate_wait;
} My;


void clear_screen(BYTE screen,int color)
{
	screen_fill_char(screen,0,0,32,32,FONT_SPACE+(color<<9));
}

int make_key_hit(int key) {
	static int _key = KEY_A;
	int keyhit;
	keyhit = (key^_key)&key;
	_key = key;
	return keyhit;
}

void color_init() {
	lcd_set_color(0x6420, 0xfca8);
	palette_set_color(0, 0x7420);	/* デフォルト */
	palette_set_color(1, 0x7422);
	palette_set_color(2, 0x7400);	/* 白床の上のキャラ */
	palette_set_color(3, 0x7402);	/* 黒床の上のキャラ */	
	palette_set_color(4, 0x2220);
	palette_set_color(5, 0x7400);	/*SCREEN2のテキストカラー */
	palette_set_color(6, 0x5420);
	palette_set_color(7, 0x4210);
	palette_set_color(8, 0x7540);	/* エンディングで使用 */
	palette_set_color(9, 0x7420);
	palette_set_color(10, 0x5421);
	palette_set_color(11, 0x0000);
	palette_set_color(12, 0x7410);	/* 自機のカラー */
	palette_set_color(13, 0x7300);
	palette_set_color(14, 0x5420);
	palette_set_color(15, 0x4210);
}

void stage_init() {
	int i;
	int j;
	display_control(0);
	font_set_monodata(FONT_SPACE, 1, space);
	font_set_colordata(FONT_MY,8,my_char);
	font_set_colordata(FONT_TAMA, 1, tama);

	text_set_screen(SCREEN2);
	screen_set_scroll(SCREEN2, 0, 0);
	screen_set_scroll(SCREEN1, 0, 0);
	sprite_set_range(0,32);
	clear_screen(SCREEN1,0);
	clear_screen(SCREEN2,5);
	text_set_palette(5);
	text_window_init(0,6,28,12,168);

	text_put_string(0,10,"おきらくだいさくせん♪ ｆｏｒ ＷｏｎｄｅｒＳｗａｎ");
	text_put_char(9,11,0x1c);
	text_put_string(10,11,"さととー ２００１");
	text_put_string(24,0,"ステージ");
	text_put_string(27,1,"面");
	text_put_string(24,3,"ブレーキ");
	text_put_string(24,4,"のこり");
	text_put_string(27,5,"回");
	text_put_string(24,7,"ＭＩＳＳ");
	text_put_string(27,8,"回");

	for (i = 0; i < 8; i++) {
		for (j = 0; j < 12; j++) {
			screen_fill_char(SCREEN1,
				j*2, i*2,2, 2,FONT_SPACE+0x0400+(i+j)%2*0x0200);
		}
	}
	display_control(DCM_SCR1 | DCM_SCR2 | DCM_SPR);
}

void title_init() {
	text_set_screen(SCREEN2);
	screen_set_scroll(SCREEN2, 0, 0);
	screen_set_scroll(SCREEN1, 0, 0);
	clear_screen(SCREEN1,0);
	clear_screen(SCREEN2,5);
	text_set_palette(5);
	text_screen_init();
	display_control(DCM_SCR1 | DCM_SCR2);
}

void title_put_string() {
	text_put_string(6,4,"おきらくだいさくせん♪");
	text_put_string(9,6,"ｆｏｒ ＷｏｎｄｅｒＳｗａｎ");
	text_put_string(8,9,"はじめる…Ａボタン");
	text_put_string(8,11,"やめる……スタートボタン");
	text_put_char(9,15,0x1c);
	text_put_string(10,15,"さととー ２００１");
}
void beep_init() {
	sound_init();
	sound_set_output( 0x0f );
	sound_set_wave( 0, wave_data );
	sound_set_pitch( 0, 1830 );
	sound_set_volume( 0, 0xff );
}

void my_init(My *my) {
	my->stage = 1;
	my->muki = 0;
	my->miss = 0;
	my->move_wait = MOVE_WAIT_DEF;
	my->rotate_wait = ROTATE_WAIT_DEF;
}

void remove_my_sprite(My *my) {
	int i;
	int j;
	for(i=0;i<2;i++) {
		for(j=0;j<2;j++) {
			sprite_set_location(my->muki*4+i*2+j,0,my->muki*8+144);
		}
	}
}

void put_my_sprite(My *my) {
	int i;
	int j;
	for(i=0;i<2;i++) {
		for(j=0;j<2;j++) {
			sprite_set_location(my->muki*4+i*2+j,
				(my->x*2+j)*8,(my->y*2+i)*8);
		}
	}
}

void rotate_my_sprite(My *my) {
	remove_my_sprite(my);
	my->muki = (my->muki + 1) % 8;
	put_my_sprite(my);
}

int move_my_sprite(My *my) {
	int i, j, k, w;
	int t = 0;
	int nx, ny;
	int dx = 0;
	int dy = 0;
	int key, keyhit;
	int flag = 0;

/* flag=0…再びループ 1…ブレーキ 2…壁と衝突 3…クリア */

	if((my->muki >= 1) && (my->muki <= 3))
		dx = 1;
	if((my->muki >= 5) && (my->muki <= 7))
		dx = -1;
	if((my->muki == 0) || (my->muki == 1) || (my->muki == 7))
		dy = -1;
	if((my->muki >= 3) && (my->muki <= 5))
		dy = 1;

	nx = my->x + dx ;
	ny = my->y + dy ;

	if(nx < 0 || nx > 11 || ny < 0 || ny > 7) 
		return 2;						/* 壁との衝突判定 */
	if(my->data[nx][ny] == 1) {
		my->data[nx][ny] = 0;
		my->rest--;						/* たまとの衝突判定 */
		t = 1;
	}

	for(k=1;k<17;k++) {
		for(i=0;i<2;i++) {
			for(j=0;j<2;j++) {
				sprite_set_location(my->muki*4+i*2+j,
				(my->x*2+j)*8+dx*k,(my->y*2+i)*8+dy*k);
				if(t==1 && k==8) {
					screen_fill_char(SCREEN1,
					(nx)*2, (ny)*2,2,2,FONT_SPACE+(nx+ny)%2*0x0200);
					sound_set_channel(1);
				}
				if(t==1 && k==10)
					sound_set_channel(0);
			}
		}
		for(w = 0; w < my->move_wait; w++) ;
		key = key_press_check();
		keyhit = make_key_hit(key);
		if((keyhit & KEY_A) && (my->brake > 0) && (flag == 0)) {
			flag = 1;
			my->brake--;
			text_put_numeric(25,5,2,0,my->brake);
		}
		if(keyhit & KEY_Y2) {			/* 裏技だよん♪ */
			for (i = 0; i < 8; i++) {
				for (j = 0; j < 12; j++) {
					screen_fill_char(SCREEN1,
					j*2, i*2,2, 2,FONT_SPACE+0x0400+(i+j)%2*0x0200);
				}
			}
			return 3;
		}
	}
	my->x = nx;
	my->y = ny;
	if(my->rest == 0)
		return 3;
	return flag;
}

void loop_my_rotate(My *my) {
	int w;
	int key, keyhit;
	int loop = 0;
	while(1) {
		for(w = 0; w < my->rotate_wait; w++) {
			sys_wait(1);
			key = key_press_check();
			keyhit = make_key_hit(key);
			if(keyhit & KEY_A) {
				loop = 1;
				break;
			}
		}
		if(loop == 1)
			break;
		rotate_my_sprite(my);
	}
}

int loop_my_move(My *my) {
	int flag;
	while(1) { 
		flag = move_my_sprite(my);
		if(flag > 0)
			break;
	}
	return flag;
}

void sprite_set() {
	int i;
	for(i=0;i<32;i++)
		sprite_set_char(i,FONT_MY + sprite_data[i]);
	for(i=0;i<24;i++)
		sprite_set_char(32+i, FONT_SPACE+0x2000);
	for(i=0;i<64;i++)
		sprite_set_location(i,0,144);
}

void put_tama(int j,int i) {
	screen_fill_char(SCREEN1,j*2,i*2,1,1,FONT_TAMA+0x0400+(i+j)%2*0x0200);
	screen_fill_char(SCREEN1,
		j*2+1,i*2,1,1,FONT_TAMA+CFM_FLIP_H+0x0400+(i+j)%2*0x0200);
	screen_fill_char(SCREEN1,
		j*2,i*2+1,1,1,FONT_TAMA+CFM_FLIP_V+0x0400+(i+j)%2*0x0200);
	screen_fill_char(SCREEN1,
		j*2+1,i*2+1,1,1,FONT_TAMA+CFM_FLIP_H+CFM_FLIP_V+0x0400+(i+j)%2*0x0200);
}

void load_stage_data(My *my) {
	int i;
	int j;
	unsigned short tmp;
	my->rest = 0;

	for(i=0;i<8;i++) {
		tmp = stage_data[(my->stage - 1) * 11 + i];
		for(j=11;j>=0;j--) {
			if((my->data[j][i] = (tmp & 0x001)) == 1) {
				my->rest++;
				put_tama(j,i);
			}
			tmp = tmp >> 1;
		}
	}
	my->x = stage_data[(my->stage - 1) * 11 + 8];
	my->y = stage_data[(my->stage - 1) * 11 + 9];
	my->brake = stage_data[(my->stage - 1) * 11 + 10];
	text_put_numeric(25,1,2,0,my->stage);
	text_put_numeric(25,5,2,0,my->brake);
	text_put_numeric(24,8,3,0,my->miss);
}

void clear_stage(My *my) {
	if(++my->stage <= LAST_STAGE) {
		text_put_string(6, 0, "にんむかんりょー！");
		text_put_string(6, 2, "つぎのステージへＧＯ！");
		text_put_string(6, 4, "《何かキーをおしてね》");
		key_wait();
		text_put_string(6,0,"         ");
		text_put_string(6,2,"           ");
		text_put_string(6,4,"           ");
	}
	else {
		text_put_string(6, 0, "全にんむかんりょー！");
		text_put_string(6, 2, "あんたはエライ！");
		text_put_string(6, 4, "《何かキーをおしてね》");
		key_wait();
		text_put_string(6,0,"          ");
		text_put_string(6,2,"        ");
		text_put_string(6,4,"           ");
	}
	make_key_hit(KEY_A);
}

int miss_window() {
	int i, j;
	int key, keyhit;
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 12; j++) {
			screen_fill_char(SCREEN1,
				j*2, i*2,2, 2,FONT_SPACE+0x0400+(i+j)%2*0x0200);
		}
	}
	text_put_string(6,0,"MISS!");
	text_put_string(6,2,"まだやる…Ａボタン");
	text_put_string(6,4,"もうやめ…スタートボタン");

	while(1) {
		key = key_press_check();
		keyhit = make_key_hit(key);
		if(keyhit & KEY_A)
			break;
		if(keyhit & KEY_START)
			return 1;
	}
	text_put_string(6,0,"     ");
	text_put_string(6,2,"         ");
	text_put_string(6,4,"            ");
	return 0;
}

int title(My *my) {
	int key, keyhit;
	title_init();
	title_put_string();

	while(1) {
		key = key_press_check();
		keyhit = make_key_hit(key);
		if(keyhit & KEY_A)
			return 1;
		if(keyhit & KEY_START)
			bios_exit();
	}
}

void settei(My *my) {
	/* 開発中 */
}

int ending(My *my) {
	return 0;
}

int play(My *my) {
	int i;
	int flag;
	stage_init();
	sprite_set();
	my_init(my);

	while(1) {
		if(my->stage > LAST_STAGE)
			return 3;
		load_stage_data(my);
		put_my_sprite(my);

		while(1) {
			loop_my_rotate(my);
			flag = loop_my_move(my);

			if(flag == 2) {
				for(i=0;i<7;i++) {
					sound_set_channel(1);
					sys_wait(1);
					sound_set_channel(0);
					sys_wait(2);
				}
				my->miss++;
				i = miss_window();
				if(i == 1)
					return 0;
				break;
			}
			if(flag == 3) {
				clear_stage(my);
				break;
			}
		}
	}
}

void main(void) {
	int now = 0; /* ０…タイトル １…プレイ ２…設定 ３…エンディング */
	static My my;
	color_init();
	beep_init();
	key_set_repeat(4,0);

	while(1) {
		switch(now) {
			case 0: now = title(&my);
					break;
			case 1: now = play(&my);
					break;
			case 2: settei(&my);
					now = 0;
					break;
			case 3: ending(&my);
					now = 0;
					break;
		}
	}
}
