#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/libwwc.h>
#include <sys/bios.h>

#define FONT_SPACE 0
#define FONT_WINDOW_BAR (FONT_SPACE + 1)
#define FONT_MY (FONT_WINDOW_BAR + 4)
#define FONT_FIELD (FONT_MY + 4)
#define FONT_FREE (FONT_FIELD + 40)

#define SPR_MY 0
#define SPR_WINDOW_BAR (SPR_MY + 4)
#define SPR_CURSOR (SPR_WINDOW_BAR + 26)

#define BLANK 0
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
#define ICE 5
#define WALL 6
#define LIGHT 7
#define DARK 8
#define GOAL 9

#define SCENE_GAMEOVER 0
#define SCENE_TITLE 1
#define SCENE_PLAY 2
#define SCENE_ENDING 3
#define FIRST_STAGE 0
#define LAST_STAGE 12
#define FIRST_SCENE SCENE_TITLE
#define SPEED_DEF 2000
#define DISP_SIZE_DEF 2
#define GO_NEXT 3
#define RETURN_TITLE 2
#define TRY_AGAIN 1
#define MENU_X 1
#define MENU_Y 9
#define WINDOW_POINT_X 172
#define WINDOW_POINT_Y ((MENU_Y + 1) * 8 - 4)
#define BEEP_START 5
#define BEEP_END 10

typedef struct {
	int x;
	int y;
	int direction;
	int speed;
	int stage;
	int field_w;
	int field_h;
	int field[16][16];
	int disp_size;
	int scroll_x;
	int scroll_y;
	int sound;
	int key;
} My;

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

BYTE window_bar[] = {
	0x00,0x00,0x00,0x0f,0x1f,0x1c,0x18,0x18, /* Šp */
	0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00, /* ‰¡ */
	0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, /* c */
	0x00,0x70,0x78,0x7c,0x7e,0x7c,0x78,0x70, /* ƒJ[ƒ\ƒ‹ */
};

unsigned short my_char[] = {
	0x0C0C, 0x1E12, 0x3F21, 0x1F13, 0x0F0C, 0x0F08, 0x1F14, 0x3F24, 
	0x7878, 0xFC8C, 0xFE02, 0xFE02, 0xFE02, 0xFC04, 0xF898, 0xF292, 
	0xFFC0, 0xFFC0, 0x3F30, 0x0F0F, 0x0101, 0x0302, 0x0705, 0x0E0E, 
	0xF909, 0xF111, 0xE1E1, 0xFD1D, 0xFE02, 0xFF81, 0x7E42, 0x3C3C, 
};

unsigned short field_char[] = {
	0x0000,0x0000,0x2020,0x0000,0x0000,0x0000,0x0404,0x0000, 
	0x0000,0x0000,0x0000,0x2020,0x0000,0x0000,0x0000,0x0404, 
	0x0000,0x0000,0x4040,0x0000,0x0000,0x0000,0x0808,0x0000, 
	0x0000,0x0000,0x0000,0x4040,0x0000,0x0000,0x0000,0x0404, 

	0x0000,0x7F7F,0x407F,0x417F,0x417F,0x437E,0x437E,0x477C, 
	0x0000,0xFEFE,0x02FE,0x82FE,0x82FE,0xC27E,0xC27E,0xE23E, 
	0x477C,0x4F79,0x4E7B,0x5C77,0x587F,0x407F,0x7F7F,0x0000, 
	0xE23E,0xF29E,0x72DE,0x3AEE,0x1AFE,0x02FE,0xFEFE,0x0000, 

	0x0000,0x7F7F,0x407F,0x587F,0x5C77,0x4E7B,0x4F79,0x477C, 
	0x0000,0xFEFE,0x02FE,0x1AFE,0x3AEE,0x72DE,0xF29E,0xE23E, 
	0x477C,0x437E,0x437E,0x417F,0x417F,0x407F,0x7F7F,0x0000, 
	0xE23E,0xC27E,0xC27E,0x82FE,0x82FE,0x02FE,0xFEFE,0x0000, 

	0x0000,0x7F7F,0x407F,0x407F,0x407F,0x417F,0x477E,0x5F78, 
	0x0000,0xFEFE,0x02FE,0x1AFE,0x7AEE,0xF29E,0xE23E,0xC27E, 
	0x5F78,0x477E,0x417F,0x407F,0x407F,0x407F,0x7F7F,0x0000, 
	0xC27E,0xE23E,0xF29E,0x7AEE,0x1AFE,0x02FE,0xFEFE,0x0000, 

	0x0000,0x7F7F,0x407F,0x587F,0x5E77,0x4F79,0x477C,0x437E, 
	0x0000,0xFEFE,0x02FE,0x02FE,0x02FE,0x82FE,0xE27E,0xFA1E, 
	0x437E,0x477C,0x4F79,0x5E77,0x587F,0x407F,0x7F7F,0x0000, 
	0xFA1E,0xE27E,0x82FE,0x02FE,0x02FE,0x02FE,0xFEFE,0x0000, 

	0x7F00,0x807B,0x8076,0x806C,0x8059,0x8033,0x8067,0x804F, 
	0xFE00,0x013E,0x017E,0x01FE,0x01FE,0x01FE,0x01FE,0x01FE, 
	0x801F,0x803F,0x807F,0x807F,0x807F,0x807F,0x807F,0x7F00, 
	0x01FE,0x01FE,0x01FC,0x01F8,0x01F2,0x01E6,0x01CE,0xFE00, 

	0x7F7F,0xC0C0,0xA0A0,0x9F9F,0x909F,0x909F,0x909F,0x909F, 
	0xFEFE,0x0303,0x0705,0xFFF9,0x0FF9,0x0FF9,0x0FF9,0x0FF9, 
	0x909F,0x909F,0x909F,0x909F,0x9F9F,0xBFA0,0xFFC0,0x7F7F, 
	0x0FF9,0x0FF9,0x0FF9,0x0FF9,0xFFF9,0xFF05,0xFF03,0xFEFE, 

	0x0101,0x0101,0x3030,0x3333,0x0707,0x0C0F,0x181F,0xD8DF, 
	0x8080,0x8080,0x0C0C,0xCCCC,0xE0E0,0x30F0,0x18F8,0x1BFB, 
	0xD8DF,0x181F,0x0C0F,0x0707,0x3333,0x3030,0x0101,0x0101, 
	0x1BFB,0x18F8,0x30F0,0xE0E0,0xCCCC,0x0C0C,0x8080,0x8080, 

	0x0000,0x7F7F,0x7F7F,0x7070,0x6E6E,0x7F7F,0x7F7F,0x7F7F, 
	0x0000,0xFEFE,0xFEFE,0x3E3E,0x0E0E,0x0E0E,0x8686,0x8686, 
	0x7F7F,0x7F7F,0x7F7F,0x6E6E,0x7070,0x7F7F,0x7F7F,0x0000, 
	0x8686,0x8686,0x0E0E,0x0E0E,0x3E3E,0xFEFE,0xFEFE,0x0000, 

	0x0000,0x0303,0x0407,0x383F,0x417F,0xFEFF,0x87FD,0xC7FF, 
	0xF8F8,0x06FE,0x39FF,0x7FC7,0xF9CF,0x31FF,0x01FF,0x01FF, 
	0x203F,0x203F,0xC0FF,0x8CFF,0x9EF3,0x9EF3,0x8DFF,0xFEFE, 
	0x19FF,0x3DE7,0x3DE7,0x1DFF,0x01FF,0x07FF,0xF8F8,0x0000, 
};

unsigned short palette_color_data[] = {
	0x0000,0x0aaa,0x00ff,0x0fff, /* ’Êí•\Ž¦ */
	0x0fff,0x0000,0x0000,0x0000, /* ”’•”½“] */
	0x00f0,0x0000,0x0000,0x0fff, /* ° */
	0x000f,0x0fff,0x00ff,0x0fff, /* –îˆó */
	0x0000,0x0888,0x00ff,0x0fff, /* ‚·‚×‚é° */
	0x0000,0x0444,0x0aaa,0x0fff, /* •Ç */
	0x0f00,0x0000,0x0ff0,0x0fff, /* –¾‚é‚­‚È‚é‚â‚Â */
	0x0000,0x0000,0x0000,0x0fff, /* ˆÃ‚­‚È‚é‚â‚Â */
	0x0000,0x0f80,0x0ff0,0x0fff, /* ”à */
	0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0f84,0x0000,0x0000, /* Ž©‹@ */
	0x0fff,0x0000,0x0000,0x0000, /* ƒEƒBƒ“ƒhƒD˜g */
	0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,
};

unsigned short palette_mono_data[] = {
	0x7530,0x0357,0x4530,0x7030,0x7530,0x7530,0x7530,0x7530,
	0x7310,0x7530,0x7530,0x7530,0x7220,0x0000,0x7530,0x7530,
};

unsigned char wave_data[] = {
	0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

char *stage_data[] = {
	"4555555555555552",
	"5565555666666555",
	"5565555555656555",
	"5565556555665555",
	"5565556555655555",
	"5565565555655555",
	"5566625356552553",
	"1555553155553595",
	"5559955555555959",
	"9994551559999995",
	"5591555555535955",
	"9999959995419555",
	"5592535554195555",
	"5594555551959555",
	"5995555559555955",
	"5555555555555555",

	"000600000000000",
	"000600023333300",
	"000300850000100",
	"023333330000100",
	"020000010000100",
	"020700010000100",
	"044506616600100",
	"000060000060100",
	"080060000060100",
	"000066666660100",
	"080060009000100",
	"000044444444100",
	"000000000000000",
	"008008008000000",
	"000000000000000",

	"0000000000000000",
	"0090000000000000",
	"0000000000000066",
	"5422323333333300",
	"5522122000000100",
	"5522132000000100",
	"5544444000000400",
	"5010000000000200",
	"5010000000000200",
	"5010000000000200",
	"0013333333333200",
	"0000000000000000",

	"233333333070",
	"271233041087",
	"261313041000",
	"271313041021",
	"255000000021",
	"261222044421",
	"231323044121",
	"213342044221",
	"213533366221",
	"223533333321",
	"296133333331",
	"444444444441",

	"455555044429",
	"577776044225",
	"577776662325",
	"566666664235",
	"155550003335",
	"255550001165",
	"566666666565",
	"577776666565",
	"577776045551",
	"455555044166",

	"000000000000000",
	"133533353333330",
	"000010000001010",
	"044415333301010",
	"005000000101010",
	"101333330101013",
	"101000100105000",
	"000020104101330",
	"044420101101010",
	"000020101001010",
	"133028101041010",
	"710044171041010",
	"000600131041010",
	"111615501001010",
	"900000100001000",

	"00090000",
	"00000000",
	"55555555",
	"14242142",
	"15554552",
	"45452515",
	"10303030",
	"25352525",
	"51545253",
	"01040201",
	"54515351",
	"25152535",
	"55555555",
	"00000000",
	"00000000",

	"033030448",
	"613041301",
	"203535001",
	"044040401",
	"261364400",
	"023030422",
	"544416922",
	"004040522",
	"233335570",
	"044144166",
	"440116666",

	"0455545550555452",
	"1354555555550255",
	"5555550555554935",
	"1585555335555353",
	"5555525162378525",
	"5555055555555545",
	"5557171035556175",
	"5110535375551581",
	"0555555545555045",
	"5155535550554555",
	"5553558545555555",
	"5152561412557215",
	"5515555353532205",
	"2555055535555550",
	"5155371375185553",
	"8555550555555555",

	"515525555535555",
	"204575583585595",
	"525555555555555",
	"555555555555525",
	"485585581574582",
	"555555515555555",
	"555555555555555",
	"585375485285585",
	"555555555555555",
	"555555555555555",
	"584585575585575",
	"155555555355553",

	"0444044504220235",
	"2103350422044402",
	"0452911505550252",
	"2105310454051405",
	"0425911205420525",
	"5205210242953102",
	"0555011202320135",
	"2404550354044103",
	"0442044405550535",
	"2405550544044102",
	"0154055193530253",
	"5405410425035303",
	"0141955205110132",
	"5491320344041205",
	"0455041493149225",
	"5505540454055493",

	"9544444444444442",
	"5415356555555552",
	"0505116525555352",
	"4155206120550552",
	"6005356604444442",
	"6266655525550562",
	"0552514444455002",
	"5550515960355552",
	"5566615600255012",
	"5562541333351012",
	"1004555555552012",
	"6205005305533412",
	"6266555245555512",
	"4504520315553352",
	"0426644555555152",
	"0333333333333333",

	"5555555555535552",
	"5555666555500265",
	"5253606555550525",
	"5565555555555535",
	"6555555556555355",
	"5556555555555555",
	"5455556555553555",
	"5555555455555155",
	"5555955555555555",
	"6555555555556555",
	"5552565555655715",
	"5655555555555655",
	"5555555555565356",
	"5554555565555555",
	"5565555555555555",
	"6555555155555565",

	"999009009",
	"900009909",
	"999009099",
	"900009009",
	"999000000",
	"000009990",
	"000009009",
	"000009009",
	"000009990",
};

int my_xy[] = {
	0,0,8,8,9,8,11,0,7,4,0,0,3,14,5,5,0,0,1,1,0,0,0,15,5,2,3,6
};

int field_wh[] = {
	16,16,15,15,16,12,12,12,12,10,15,15,8,15,9,11,16,16,15,12,16,16,16,16,16,16,9,9
};

int field_disp_size[] = {
	4,3,2,0,2,1,2,1,4,1,4,1,3,4
};

char *title_menu[] = {
	"ƒQ[ƒ€ƒXƒ^[ƒg",
	"ƒQ[ƒ€‚ð‚â‚ß‚é",
	"ƒLƒƒƒ“ƒZƒ‹"
};

char *play_menu[] = {
	"ƒLƒƒƒ“ƒZƒ‹",
	"ƒŠƒXƒ^[ƒg",
	"ƒ^ƒCƒgƒ‹‚Ö"
};

char *clear_text[] = {
	"CLEAR‚¾I",
	"‚ ‚ñ‚½‚ÍƒGƒ‰ƒCI",
	"push key"
};

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

void clear_text_screen(int x, int y, int w, int h) {
	int i;
	static char clear_text[32];
	for(i=0;i<w;i++)
		clear_text[i] = ' ';
	clear_text[i] = '\0';
	for(i=0;i<h;i++)
		text_put_string(x, y+i, clear_text);
}

void color_screen_init() {
	int i,j;
	wwc_set_color_mode(COLOR_MODE_4COLOR);
	wwc_clear_font();
	for(i=0;i<16;i++) {
		for(j=0;j<4;j++)
			wwc_palette_set_color(i, 3-j, palette_color_data[i*4+j]);
	}
}

void mono_screen_init() {
	int i;
	wwc_set_color_mode(COLOR_MODE_GRAYSCALE);
	lcd_set_color(0x6420, 0xfca8);
	for(i=0;i<16;i++)
		palette_set_color(i, palette_mono_data[i]);
}

void screen_init() {
	if(wwc_get_hardarch() == HARDARCH_WSC)
		color_screen_init();
	else
		mono_screen_init();
	
	font_set_monodata(FONT_SPACE, 1, space);
	font_set_monodata(FONT_WINDOW_BAR, 4, window_bar);
	font_set_colordata(FONT_MY, 4, my_char);
	font_set_colordata(FONT_FIELD, 40, field_char);


	clear_screen(SCREEN1,0);
	clear_screen(SCREEN2,1);
	screen_set_scroll(SCREEN1, 0, 0);
	screen_set_scroll(SCREEN2, 0, 0);
	text_set_palette(1);
	text_window_init(18,0,10,18,FONT_FREE);
	sprite_set_range(0,31);
}

void beep_init() {
	sound_init();
	sound_set_output( 0x0f );
	sound_set_wave( 0, wave_data );
	sound_set_pitch( 0, 1830 );
	sound_set_volume( 0, 0x88 );
}

void disp_text_title() {
	text_put_string(0, 0, "+--------+");
	text_put_string(0, 1, "b‚ê‚ ôƒ`[ƒY  b");
	text_put_string(0, 2, "b  ‚†‚‚’ wsb");
	text_put_string(0, 3, "b        b");
	text_put_string(0, 4, "b  ‚³‚Æ‚Æ[  b");
	text_put_char(2, 4, 0x1c);
	text_put_string(0, 5, "+--------+");
}

void disp_wait(My *my) {
	text_put_string(1, 16, "‚r‚n‚t‚m‚cF");
	if(my->sound)
		text_put_string(7, 16, "ON ");
	else
		text_put_string(7, 16, "OFF");
	text_put_string(1, 17, "‚v‚`‚h‚sF");
	text_put_numeric(6, 17, 4, 0, my->speed);
}

void play_init(My *my) {
	int i;
	display_control(0);
	srand(sys_get_tick_count() & 0x7fff);
	my->stage = FIRST_STAGE;
	my->speed = SPEED_DEF;
	my->scroll_x = 0;
	my->scroll_y = 0;
	my->sound = 1;
	for(i=SPR_MY;i<SPR_MY+4;i++)
		sprite_set_char_location(i,FONT_MY+i+0x2800, 0, 144);
	sprite_set_char(SPR_WINDOW_BAR  ,FONT_WINDOW_BAR+0x2a00);
	sprite_set_char(SPR_WINDOW_BAR+1,FONT_WINDOW_BAR+0x6a00);
	sprite_set_char(SPR_WINDOW_BAR+2,FONT_WINDOW_BAR+0xaa00);
	sprite_set_char(SPR_WINDOW_BAR+3,FONT_WINDOW_BAR+0xea00);
	for(i=SPR_WINDOW_BAR+4;i<SPR_WINDOW_BAR+20;i++)
		sprite_set_char(i, FONT_WINDOW_BAR + 1 + 0x2a00);
	for(i=SPR_WINDOW_BAR+20;i<SPR_WINDOW_BAR+26;i++)
		sprite_set_char(i, FONT_WINDOW_BAR + 2 + 0x2a00);
	for(i=SPR_WINDOW_BAR;i<SPR_WINDOW_BAR+26;i++)
		sprite_set_location(i, 0, 144);
	sprite_set_char_location(SPR_CURSOR, FONT_WINDOW_BAR+0x2a03, 0, 144);
	disp_text_title();
}

void load_stage_data(My *my) {
	int i,j,data_index;
	data_index = 0;
	my->x = my_xy[my->stage * 2];
	my->y = my_xy[my->stage * 2 + 1];
	my->disp_size = field_disp_size[my->stage];
	my->field_w = field_wh[my->stage * 2];
	my->field_h = field_wh[my->stage * 2 + 1];
	for(i=0;i<my->stage;i++)
		data_index += field_wh[i * 2 + 1];
	for(i=0;i<my->field_h;i++) {
		for(j=0;j<my->field_w;j++)
			my->field[j][i] = stage_data[data_index + i][j] - 0x30;
	}
}

void disp_all_field(My *my) {
	int i,j,color;
	for(i=0;i<my->field_h;i++) {
		for(j=0;j<my->field_w;j++) {
			if(my->field[j][i] == BLANK)
				color = 2 << 9;
			else if(my->field[j][i] <= RIGHT)
				color = 3 << 9;
			else
				color = my->field[j][i]-1 << 9;
			screen_fill_char(SCREEN1, j*2  , i*2  ,
					1, 1, FONT_FIELD     + my->field[j][i]*4 + color);
			screen_fill_char(SCREEN1, j*2+1, i*2  ,
					1, 1, FONT_FIELD + 1 + my->field[j][i]*4 + color);
			screen_fill_char(SCREEN1, j*2  , i*2+1,
					1, 1, FONT_FIELD + 2 + my->field[j][i]*4 + color);
			screen_fill_char(SCREEN1, j*2+1, i*2+1,
					1, 1, FONT_FIELD + 3 + my->field[j][i]*4 + color);
		}
	}
}

void clip_field(My *my) {
	int i;
	int px, py, sx, sy;
	if(my->x < my->disp_size) {
		sx = 0;
		px = my->x;
	}
	else if(my->x >= my->field_w - my->disp_size) {
		sx = my->field_w - my->disp_size * 2 -1;
		px = my->disp_size * 2 - (my->field_w - my->x) + 1;
	}
	else {
		sx = my->x - my->disp_size;
		px = my->disp_size;
	}
	if(my->y < my->disp_size) {
		sy = 0;
		py = my->y;
	}
	else if(my->y >= my->field_h - my->disp_size) {
		sy = my->field_h - my->disp_size * 2 - 1;
		py = my->disp_size * 2 - (my->field_h - my->y) + 1;
	}
	else {
		sy = my->y - my->disp_size;
		py = my->disp_size;
	}
	i = 4 - my->disp_size;
	sx -= i;
	sy -= i;
	px += i;
	py += i;
	screen_set_scroll(SCREEN1, my->scroll_x = sx * 16, my->scroll_y = sy * 16);
	screen2_set_window(i*16, i*16, 143 - i*32, 143 - i*32);
	for(i=0;i<4;i++)
		sprite_set_location(i, px*16+(i%2)*8, py*16+(i/2)*8);
}

void disp_stage_num(My *my) {
	clear_text_screen(0, 6, 10, 10);
	if(my->stage == FIRST_STAGE) {
		text_put_string(1, 7, "ôƒI[ƒgƒfƒ‚ô");
		text_put_string(1, 9, "Aƒ{ƒ^ƒ“‚ð‚¨‚µ‚Ä‚Ë");
		text_put_string(1, 12, "‚¨‚Õ‚µ‚å‚ñ");
		text_put_string(1, 13, "‚¨‚ÆFY4");
		text_put_string(1, 14, "‚Í‚â‚³FY1‚ÆY3");
	}
	else {
		text_put_string(1, 7, "‚r‚s‚`‚f‚dF");
		text_put_numeric(7,7,2,0,my->stage);
	}
}

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

int move_up(My *my, int sound) {
	int i, j, s, sx, sy;
	s = sprite_get_location(0);
	sy = (s >> 8);
	sx = (s & 0x00ff);
	if(my->y == 0 || my->field[my->x][my->y-1] == WALL)
		return FALSE;
	my->direction = UP;
	if(my->y <= my->disp_size || my->y > my->field_h -my->disp_size - 1) {
		for(i=0;i<16;i++) {
			if(sound && i == BEEP_START)
				sound_set_channel(1);
			if(sound && i == BEEP_END)
				sound_set_channel(0);
			sy--;
			for(j=0;j<4;j++)
				sprite_set_location(j, sx+(j%2)*8, sy+(j/2)*8);
			for(j=0;j<my->speed;j++);
			my->key = my->key | make_key_hit(key_press_check());
		}
		my->y--;
		return TRUE;
	}
	for(i=0;i<16;i++) {
		if(sound && i == BEEP_START)
			sound_set_channel(1);
		if(sound && i == BEEP_END)
			sound_set_channel(0);
		screen_set_scroll(SCREEN1, my->scroll_x, --my->scroll_y);
		for(j=0;j<my->speed;j++);
		my->key = my->key | make_key_hit(key_press_check());
	}
	my->y--;
	return TRUE;
}

int move_down(My *my, int sound) {
	int i, j, s, sx, sy;
	s = sprite_get_location(0);
	sy = (s >> 8);
	sx = (s & 0x00ff);
	if(my->y == my->field_h - 1 || my->field[my->x][my->y+1] == WALL)
		return FALSE;
	my->direction = DOWN;
	if(my->y < my->disp_size || my->y >= my->field_h - my->disp_size - 1) {
		for(i=0;i<16;i++) {
			if(sound && i == BEEP_START)
				sound_set_channel(1);
			if(sound && i == BEEP_END)
				sound_set_channel(0);
			sy++;
			for(j=0;j<4;j++)
				sprite_set_location(j, sx+(j%2)*8, sy+(j/2)*8);
			for(j=0;j<my->speed;j++);
			my->key = my->key | make_key_hit(key_press_check());
		}
		my->y++;
		return TRUE;
	}
	for(i=0;i<16;i++) {
		if(sound && i == BEEP_START)
			sound_set_channel(1);
		if(sound && i == BEEP_END)
			sound_set_channel(0);
		screen_set_scroll(SCREEN1, my->scroll_x, ++my->scroll_y);
		for(j=0;j<my->speed;j++);
		my->key = my->key | make_key_hit(key_press_check());
	}
	my->y++;
	return TRUE;
}

int move_left(My *my, int sound) {
	int i, j, s, sx, sy;
	s = sprite_get_location(0);
	sy = (s >> 8);
	sx = (s & 0x00ff);
	if(my->x == 0 || my->field[my->x-1][my->y] == WALL)
		return FALSE;
	my->direction = LEFT;
	if(my->x <= my->disp_size || my->x > my->field_w - my->disp_size - 1) {
		for(i=0;i<16;i++) {
			if(sound && i == BEEP_START)
				sound_set_channel(1);
			if(sound && i == BEEP_END)
				sound_set_channel(0);
			sx--;
			for(j=0;j<4;j++)
				sprite_set_location(j, sx+(j%2)*8, sy+(j/2)*8);
			for(j=0;j<my->speed;j++);
			my->key = my->key | make_key_hit(key_press_check());
		}
		my->x--;
		return TRUE;
	}
	for(i=0;i<16;i++) {
		if(sound && i == BEEP_START)
			sound_set_channel(1);
		if(sound && i == BEEP_END)
			sound_set_channel(0);
		screen_set_scroll(SCREEN1, --my->scroll_x, my->scroll_y);
		for(j=0;j<my->speed;j++);
		my->key = my->key | make_key_hit(key_press_check());
	}
	my->x--;
	return TRUE;
}

int move_right(My *my, int sound) {
	int i, j, s, sx, sy;
	s = sprite_get_location(0);
	sy = (s >> 8);
	sx = (s & 0x00ff);
	if(my->x == my->field_w - 1 || my->field[my->x+1][my->y] == WALL)
		return FALSE;
	my->direction = RIGHT;
	if(my->x < my->disp_size || my->x >= my->field_w - my->disp_size - 1) {
		for(i=0;i<16;i++) {
			if(sound && i == BEEP_START)
				sound_set_channel(1);
			if(sound && i == BEEP_END)
				sound_set_channel(0);
			sx++;
			for(j=0;j<4;j++)
				sprite_set_location(j, sx+(j%2)*8, sy+(j/2)*8);
			for(j=0;j<my->speed;j++);
			my->key = my->key | make_key_hit(key_press_check());
		}
		my->x++;
		return TRUE;
	}
	for(i=0;i<16;i++) {
		if(sound && i == BEEP_START)
			sound_set_channel(1);
		if(sound && i == BEEP_END)
			sound_set_channel(0);
		screen_set_scroll(SCREEN1, ++my->scroll_x, my->scroll_y);
		for(j=0;j<my->speed;j++);
		my->key = my->key | make_key_hit(key_press_check());
	}
	my->x++;
	return TRUE;
}

move_ice(My *my) {
	int i;
	switch(my->direction) {
	case UP :
		i = move_up(my, 0);
		break;
	case DOWN :
		i = move_down(my, 0);
		break;
	case LEFT :
		i = move_left(my, 0);
		break;
	case RIGHT :
		i = move_right(my, 0);
		break;
	}
	return i;
}

void size_up(My *my) {
	int i;
	my->disp_size++;
	clip_field(my);
	if(my->sound) {
		for(i=0;i<4;i++) {
			sound_set_channel(1);
			sys_wait(1);
			sound_set_channel(0);
			sys_wait(2);
		}
	}
	else
		sys_wait(12);
}

void size_down(My *my) {
	int i;
	my->disp_size--;
	clip_field(my);
	if(my->sound) {
		for(i=0;i<4;i++) {
			sound_set_channel(1);
			sys_wait(1);
			sound_set_channel(0);
			sys_wait(2);
		}
	}
	else
		sys_wait(12);

}

void disp_window_bar(int i) {
	int j;
	for(j=0;j<4;j++) {
		sprite_set_location(SPR_WINDOW_BAR+j,
			WINDOW_POINT_X-i+(j%2)*(16+i*2),WINDOW_POINT_Y-i*3/7+(j/2)*(8+i*3/7*2));
		sprite_set_location(SPR_WINDOW_BAR+j+4,
			WINDOW_POINT_X-i+(j%2)*(i*2)+8,WINDOW_POINT_Y-i*3/7+(j/2)*(8+i*3/7*2));
		sprite_set_location(SPR_WINDOW_BAR+j+8,
			WINDOW_POINT_X-i*5/7+(j%2)*(i*5/7*2)+8,WINDOW_POINT_Y-i*3/7+(j/2)*(8+i*3/7*2));
		sprite_set_location(SPR_WINDOW_BAR+j+12,
			WINDOW_POINT_X-i*3/7+(j%2)*(i*3/7*2)+8,WINDOW_POINT_Y-i*3/7+(j/2)*(8+i*3/7*2));
		sprite_set_location(SPR_WINDOW_BAR+j+16,
			WINDOW_POINT_X-i*1/7+(j%2)*(i*1/7*2)+8,WINDOW_POINT_Y-i*3/7+(j/2)*(8+i*3/7*2));
		sprite_set_location(SPR_WINDOW_BAR+j+20,
			WINDOW_POINT_X-i+(j%2)*(16+i*2),WINDOW_POINT_Y-i*2/7+(j/2)*(i*2/7*2)+4);
	}
	for(j=0;j<2;j++)
		sprite_set_location(SPR_WINDOW_BAR+j+24,
			WINDOW_POINT_X-i+(j%2)*(16+i*2), WINDOW_POINT_Y + 4);
	sys_wait(1);
}
void open_window_bar() {
	int i;
	for(i=1;i<=28;i++)
		disp_window_bar(i);
}

void close_window_bar() {
	int i;
	for(i=28;i>=0;i--)
		disp_window_bar(i);
	for(i=SPR_WINDOW_BAR;i<SPR_WINDOW_BAR+26;i++)
		sprite_set_location(i, 0, 144);
}

void open_menu(char **str, int i) {
	clear_text_screen(0, 6, 10, 9);
	open_window_bar();
	text_put_string(MENU_X + i, MENU_Y    , str[0]);
	text_put_string(MENU_X + i, MENU_Y + 1, str[1]);
	text_put_string(MENU_X + i, MENU_Y + 2, str[2]);
}

int select_menu(My *my, int cancel) {
	int i, key, keyhit;
	i = 0;
	while(1) {
		key = key_press_check();
		keyhit = make_key_hit(key);
		if(keyhit & KEY_A)
			break;
		if(keyhit & KEY_B) {
			i = cancel;
			break;
		}
		if((keyhit & KEY_X1) && i > 0)
			i--;
		if((keyhit & KEY_X3) && i < 2)
			i++;
		sprite_set_location(SPR_CURSOR, 152, 72+i*8);
	}
	sprite_set_location(SPR_CURSOR, 0, 144);
	return i;
}

void close_menu(My *my) {
	clear_text_screen(MENU_X, MENU_Y, 8, 3);
	close_window_bar();
}

int play_loop(My *my) {
	int i;
	int key, keyhit;
	while(1) {
		key = key_press_check();
		keyhit = make_key_hit(key) | my->key;
		my->key = 0;
		if(keyhit & KEY_A) {
			if(my->stage != 0) {
				open_menu(play_menu, 1);
				i = select_menu(my, 0);
				close_menu(my);
				if(i)
					break;
			}
			else {
				open_menu(title_menu, 1);
				i = select_menu(my, 2);
				close_menu(my);
				if(i == 0) {
					i = GO_NEXT;
					break;
				}
				else if(i == 1) {
					bios_exit();
					break;
				}
			}
			disp_stage_num(my);
		}
		if(key & KEY_Y2) {		/* — ‹Z‚¾‚æ‚ñô */
			i = GO_NEXT;
			break;
		}
		if(keyhit & KEY_Y4) {
			my->sound ^= 1;
			disp_wait(my);
			continue;
		}
		if(my->field[my->x][my->y] == GOAL) {
			i = GO_NEXT;
			break;
		}
		if((key & KEY_Y1) && my->speed < 9999) {
			my->speed++;
			disp_wait(my);
			continue;
		}
		if((key & KEY_Y3) && my->speed > 0) {
			my->speed--;
			disp_wait(my);
			continue;
		}
		if(my->field[my->x][my->y] == ICE && move_ice(my))
			continue;
		if(my->field[my->x][my->y] == UP && move_up(my ,my->sound))
			continue;
		if(my->field[my->x][my->y] == DOWN && move_down(my, my->sound))
			continue;
		if(my->field[my->x][my->y] == LEFT && move_left(my, my->sound))
			continue;
		if(my->field[my->x][my->y] == RIGHT && move_right(my, my->sound))
			continue;
		if(my->field[my->x][my->y] == LIGHT && my->disp_size < 4) {
			my->field[my->x][my->y] = BLANK;
			screen_fill_char(SCREEN1, my->x*2  , my->y*2  , 1, 1, FONT_FIELD  );
			screen_fill_char(SCREEN1, my->x*2+1, my->y*2  , 1, 1, FONT_FIELD+1);
			screen_fill_char(SCREEN1, my->x*2  , my->y*2+1, 1, 1, FONT_FIELD+2);
			screen_fill_char(SCREEN1, my->x*2+1, my->y*2+1, 1, 1, FONT_FIELD+3);
			size_up(my);
		}
		if(my->field[my->x][my->y] == DARK && my->disp_size > 0) {
			my->field[my->x][my->y] = BLANK;
			screen_fill_char(SCREEN1, my->x*2  , my->y*2  , 1, 1, FONT_FIELD  );
			screen_fill_char(SCREEN1, my->x*2+1, my->y*2  , 1, 1, FONT_FIELD+1);
			screen_fill_char(SCREEN1, my->x*2  , my->y*2+1, 1, 1, FONT_FIELD+2);
			screen_fill_char(SCREEN1, my->x*2+1, my->y*2+1, 1, 1, FONT_FIELD+3);
			size_down(my);
		}
		if(key & KEY_X1 && move_up(my, 0))
			continue;
		if(key & KEY_X3 && move_down(my, 0))
			continue;
		if(key & KEY_X4 && move_left(my, 0))
			continue;
		if(key & KEY_X2 && move_right(my, 0))
			continue;
	}
	return i;
}

void go_next(My *my) {
	if(my->stage != FIRST_STAGE) {
		open_menu(clear_text, 0);
		key_wait();
		close_menu(my);
	}
	my->stage++;
}

void disp_staff() {
	text_put_string(1, 7, "Ending");
	text_put_string(1, 9, "‚ê‚ ôƒ`[ƒY");
	sys_wait(50);
	text_put_string(2, 11, "‚r‚s‚`‚e‚e");
	sys_wait(200);
	clear_text_screen(0, 9, 10, 3);
	sys_wait(100);
	text_put_string(1, 9, "ƒvƒƒOƒ‰ƒ€");
	sys_wait(50);
	text_put_string(2,11, "‚³‚Æ‚Æ[");
	sys_wait(200);
	clear_text_screen(0, 9, 10, 3);
	sys_wait(100);
	text_put_string(1, 9, "ƒXƒe[ƒWì¬");
	sys_wait(50);
	text_put_string(2,11, "‚f‚fƒAƒcƒV");
	sys_wait(50);
	text_put_string(2,13, "ç—t Ž˜Y");
	sys_wait(200);
	clear_text_screen(0, 11, 10, 3);
	text_put_string(2,11,"]ŒË Œ’");
	sys_wait(50);
	text_put_string(2,13,"‰¡ŽR ’¼l");
	sys_wait(200);
	clear_text_screen(0, 9, 10, 5);
	sys_wait(100);
	text_put_string(1, 9, "ƒeƒXƒgƒvƒŒƒC");
	sys_wait(50);
	text_put_string(2,11, "¼’JŒ¤‚Ì‚Ý‚ñ‚È");
	sys_wait(50);
	text_put_string(2,13, "‚x‚`‚m");
	sys_wait(200);
	clear_text_screen(0, 9, 10, 5);
	sys_wait(100);
	text_put_string(1, 9, "ƒXƒyƒVƒƒƒ‹");
	text_put_string(4,10, "ƒTƒ“ƒNƒX");
	sys_wait(50);
	text_put_string(1,12, "’†“‡‚³‚ñ");
	sys_wait(50);
	text_put_string(1,14,"‚s‚uƒQ[ƒ€‚j‚`‚h");
	sys_wait(200);
	clear_text_screen(0, 12, 12, 3);
	text_put_string(1, 12, "‚‚Ž‚„ ‚™‚‚•D");
	sys_wait(200);
	clear_text_screen(0, 9, 10, 4);
	sys_wait(100);
	text_put_string(1, 9, "‚±‚Ò[‚ç‚¢‚Æ");
	sys_wait(50);
	text_put_char(2,11, 0x1c);
	text_put_string(3,11, "‚³‚Æ‚Æ[");
	sys_wait(200);
	clear_text_screen(0, 9, 10, 3);
	sys_wait(100);
	text_put_string(1, 10, "™ ‚¨‚µ‚Ü‚¢ ™");
	sys_wait(50);
	text_put_string(1, 14, "‰½‚©ƒL[‚ð‚¨‚µ‚Ä");
	key_wait();
	make_key_hit(KEY_A);
}

void ending(My *my) {
	display_control(DCM_SCR2 | DCM_SPR | DCM_SCR2_WIN_OUTSIDE);
	clear_text_screen(0, 15, 10, 3);
	load_stage_data(my);
	disp_all_field(my);
	clip_field(my);
	display_control(DCM_SCR1 | DCM_SCR2 | DCM_SPR | DCM_SCR2_WIN_OUTSIDE);
	disp_staff();
}

void play(My *my) {
	int i;
	while(1) {
		my->stage = FIRST_STAGE;
		while(my->stage <= LAST_STAGE) {
			display_control(DCM_SCR2 | DCM_SPR | DCM_SCR2_WIN_OUTSIDE);
			load_stage_data(my);
			disp_all_field(my);
			clip_field(my);
			disp_stage_num(my);
			disp_wait(my);
			display_control(DCM_SCR1 | DCM_SCR2 | DCM_SPR | DCM_SCR2_WIN_OUTSIDE);
			i = play_loop(my);
			switch(i) {
			case GO_NEXT :
				go_next(my);
				break;
			case RETURN_TITLE :
				my->stage = FIRST_STAGE;
				break;;
			case TRY_AGAIN :
				break;
			}
		}
		ending(my);
	}
}

int main() {
	static My my;
	screen_init();
	beep_init();
	play_init(&my);
	play(&my);
}
