#include <string.h>		/* strlen */
#include "apilib.h"

void putstr(int win, int *winbuf, int x, int y, int col, unsigned char *s);
void putstr_def(int win, int *winbuf, int x, int y, int col, unsigned char *s);
void wait(int i, int timer, char *keyflag);
void setdec8(char *s, int i);

static unsigned char charset[16 * 8] = {

	/* invader(0) */
	0x00,0x00,0x00,0x03,0x07,0x07,0x07,0x07,
	0x07,0x07,0x00,0x01,0x03,0x07,0x06,0x00,

	/* invader(1) */
	0x00,0x0F,0x7F,0xFF,0xFF,0xCF,0xCF,0xFF,
	0xFF,0xFF,0xEC,0xCC,0x8E,0x06,0x00,0x00,

	/* invader(2) */
	0x00,0xF0,0xFE,0xFF,0xFF,0xF3,0xF3,0xFF,
	0xFF,0xFF,0x37,0x33,0x71,0x60,0x00,0x00,

	/* invader(3) */
	0x00,0x00,0x00,0xC0,0xE0,0xE0,0xE0,0xE0,
	0xE0,0xE0,0x00,0x80,0xC0,0xE0,0x60,0x00,

	/* fighter(0) */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,
	0x13,0x17,0x1F,0x1F,0x1F,0x1F,0x1F,0x00,

	/* fighter(1) */
	0x00,0x3C,0x7E,0x66,0xC3,0xC3,0xC3,0xFF,
	0xFF,0xFF,0xFF,0xBD,0xBD,0xA5,0xE7,0x00,

	/* fighter(2) */
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,
	0xC8,0xE8,0xF8,0xF8,0xF8,0xF8,0xF8,0x00,

	/* laser */
	0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
	0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00
};
/* invader:"abcd", fighter:"efg", laser:"h" */

int delay = 0;

void HariMain(void)
{
	int win, timer, i, j, fx, laserwait, lx[128], ly[128];
	int ix, iy, movewait0, movewait, idir;
	int lnum = 0;
	int combo = 0;
	int stage;
	int mmm;
	int invline, score, high, point;
	int winbuf[336 * 262];
	unsigned char invstr[32 * 6], s[12], keyflag[4], *p;
	static char invstr0[32] = " abcd abcd abcd abcd abcd ";
	//struct ENV env_t;
	char stage_s[64];

	win = api_openwin(winbuf, 336, 261, -1, "invader like TAITO");
	
	api_boxfilwin(win, 6, 27, 329, 254, api_getint(0));
	timer = api_alloctimer();
	api_inittimer(timer, 128);
	
	/*putstr_def(win, winbuf, 0, 0, 7, "DARETOKU INVADER OK_");
	
	api_beepEx(1000000,18);
	api_beepEx(2000000,18);*/

	/*int hhhh;
	for(hhhh = 0;hhhh < 1024;hhhh++) {
		env_t.offset[hhhh] = hhhh;
	}

	api_beep8(env_t, 440000, 1024*10);*/

	putstr_def(win, winbuf, (40 / 2) - (strlen("ｉｎｖａｄｅｒ") / 2), 2, api_getint(2), "ｉｎｖａｄｅｒ");
	putstr_def(win, winbuf, (40 / 2) - (strlen("like TAITO") / 2), 2 + 1, api_getint(7), "like TAITO");
	putstr_def(win, winbuf, (40 / 2) - (strlen("Press any key of start") / 2), (15 / 2), api_getint(1), "Press any key of start");
	
	api_getkey(1);
	api_boxfilwin(win, 6, 27, 329, 254, api_getint(0));

	high = 0;
	putstr(win, winbuf, 22, 0, api_getint(7), "HIGH:00000000");

restart:
	score = 0;
	point = 1000;
	combo = 0;
	stage = 0;
	putstr(win, winbuf,  4, 0, api_getint(7), "SCORE:00000000");
	movewait0 = 20;
	fx = 18;
	putstr(win, winbuf, fx, 13, api_getint(8), "efg");
	sprintf(stage_s, "STAGE %d", stage + 1);
	putstr_def(win, winbuf, (40 / 2) - ((strlen(stage_s) - 1) / 2), (15 / 2), api_getint(4), stage_s);
	wait(100, timer, keyflag);
	putstr_def(win, winbuf, (40 / 2) - ((strlen(stage_s) - 1) / 2), (15 / 2), api_getint(0), stage_s);

next_group:
	sprintf(stage_s, "STAGE %d", stage + 1);
	putstr_def(win, winbuf, (40 / 2) - ((strlen(stage_s) - 1) / 2), (15 / 2), api_getint(4), stage_s);
	wait(100, timer, keyflag);
	putstr_def(win, winbuf, (40 / 2) - ((strlen(stage_s) - 1) / 2), (15 / 2), api_getint(0), stage_s);
	ix = 7;
	iy = 1;
	invline = 6;
	for (i = 0; i < 6; i++) {
		for (j = 0; j < 27; j++) {
			invstr[i * 32 + j] = invstr0[j];
		}
		putstr(win, winbuf, ix, iy + i, api_getint(4), invstr + i * 32);
	}
	keyflag[0] = 0;
	keyflag[1] = 0;
	keyflag[2] = 0;

	for(mmm = 0; mmm < 128; mmm++) {
		if(ly[mmm] != 0)putstr(win, winbuf, lx[mmm], ly[mmm], api_getint(0), " ");
		ly[mmm] = 0; /* 非表示 */
		lx[mmm] - 0;
	}
	putstr(win, winbuf, 22, 0, api_getint(7), "HIGH:00000000");
	putstr(win, winbuf,  4, 0, api_getint(7), "SCORE:00000000");
	for (i = 0; i < invline; i++) {
		putstr(win, winbuf, ix, iy + i, api_getint(4), invstr + i * 32);
	}
	putstr(win, winbuf, fx, 13, api_getint(8), "efg ");
	setdec8(s, score);
	putstr(win, winbuf, 10, 0, api_getint(7), s);
	setdec8(s, high);
	putstr(win, winbuf, 27, 0, api_getint(7), s);
	laserwait = 0;
	movewait = movewait0;
	idir = +1;
	wait(100, timer, keyflag);

	for (;;) {
		if (laserwait != 0) {
			laserwait--;
			keyflag[2 /* space */] = 0;
		}

		wait(2, timer, keyflag);

		/* 自機の処理 */
		if (keyflag[0 /* left */]  != 0 && fx > 0) {
			fx--;
			putstr(win, winbuf, fx, 13, api_getint(8), "efg ");
			keyflag[0 /* left */]  = 0;
		}
		if (keyflag[1 /* right */] != 0 && fx < 37) {
			putstr(win, winbuf, fx, 13, api_getint(8), " efg");
			fx++;
			keyflag[1 /* right */] = 0;
		}
		if (keyflag[2 /* space */] != 0 && laserwait == 0) {
			laserwait = 1;
			lx[lnum] = fx + 1;
			ly[lnum] = 13;
			lnum++;
			if(lnum == 128) lnum = 0;
		}

		/* インベーダ移動 */
		if (movewait != 0) {
			movewait--;
		} else {
			movewait = movewait0;
			if (ix + idir > 14 || ix + idir < 0) {
				if (iy + invline == 13) {
					break; /* GAME OVER */
				}
				idir = - idir;
				putstr(win, winbuf, ix + 1, iy, api_getint(0), "                         ");
				iy++;
			} else {
				ix += idir;
			}
			for (i = 0; i < invline; i++) {
				putstr(win, winbuf, ix, iy + i, api_getint(4), invstr + i * 32);
			}
		}

		/* レーザー処理 */
		for(mmm = 0; mmm < 128; mmm++) {
			if (ly[mmm] > 0) {
				if (ly[mmm] < 13) {
					if (ix < lx[mmm] && lx[mmm] < ix + 25 && iy <= ly[mmm] && ly[mmm] < iy + invline) {
						putstr(win, winbuf, ix, ly[mmm], api_getint(4), invstr + (ly[mmm] - iy) * 32);
					} else {
						putstr(win, winbuf, lx[mmm], ly[mmm], api_getint(0), " ");
					}
				}
				ly[mmm]--;
				if (ly[mmm] > 0) {
					putstr(win, winbuf, lx[mmm], ly[mmm], api_getint(3), "h");
				}
				if (ix < lx[mmm] && lx[mmm] < ix + 25 && iy <= ly[mmm] && ly[mmm] < iy + invline) {
					p = invstr + (ly[mmm] - iy) * 32 + (lx[mmm] - ix);
					if (*p != ' ') {
						/* hit ! */
						score += point + (combo * 200);
						setdec8(s, score);
						putstr(win, winbuf, 10, 0, api_getint(7), s);
						if (high < score) {
							high = score;
							putstr(win, winbuf, 27, 0, api_getint(7), s);
						}
						for (p--; *p != ' '; p--) { }
						for (i = 1; i < 5; i++) {
							p[i] = ' ';
						}
						putstr(win, winbuf, ix, ly[mmm], api_getint(4), invstr + (ly[mmm] - iy) * 32);
						for (; invline > 0; invline--) {
							for (p = invstr + (invline - 1) * 32; *p != 0; p++) {
								if (*p != ' ') {
									goto alive;
								}
							}
						}
						/* 全部やっつけられた */
						movewait0 -= movewait0 / 6;
						stage++;
						if(stage == 256) goto the_end;
						goto next_group;
		alive:
						ly[mmm] = 0;
					}
				}
			}
		}
	}

	/* GAME OVER */
	putstr(win, winbuf, (40 / 2) - (strlen("GAME OVER") / 2), 6, api_getint(1), "GAME OVER");
	wait(0, timer, keyflag);
	for (i = 1; i < 14; i++) {
		putstr(win, winbuf, 0, i, api_getint(0), "                                        ");
	}
	goto restart;
	
the_end:
	putstr(win, winbuf, (40 / 2) - (strlen("THE END") / 2), 7, api_getint(7), "THE END");
	putstr(win, winbuf, (40 / 2) - (strlen("INVADER IS DEAD ALL!") / 2), 8, api_getint(1), "INVADER IS DEAD ALL!");
	wait(0, timer, keyflag);
	api_end();
}

void putfont8(int *vram, int xsize, int x, int y, int c, char *font)
{
	int i;
	int xc, yc;
	int *p, d;
	char c1, c2;
	
	int i2 = 0;
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) { p[0] = c; }
		if ((d & 0x40) != 0) { p[1] = c; }
		if ((d & 0x20) != 0) { p[2] = c; }
		if ((d & 0x10) != 0) { p[3] = c; }
		if ((d & 0x08) != 0) { p[4] = c; }
		if ((d & 0x04) != 0) { p[5] = c; }
		if ((d & 0x02) != 0) { p[6] = c; }
		if ((d & 0x01) != 0) { p[7] = c; }
	}
	
	return;
}

void putstr(int win, int *winbuf, int x, int y, int col, unsigned char *s)
{
	int c, x0, i;
	unsigned char *p, t[2];
	x = x * 8 + 8;
	y = y * 16 + 29;
	x0 = x;
	i = strlen(s);	/* sの文字数を数える */
	api_boxfilwin(win + 1, x, y, x + i * 8 - 1, y + 15, api_getint(0));
	t[1] = 0;
	for (;;) {
		c = *s;
		if (c == 0) {
			break;
		}
		if (c != ' ') {
			if ('a' <= c && c <= 'h') {
				p = charset + 16 * (c - 'a');
				putfont8(winbuf, 336, x, y, col, p);
			} else {
				t[0] = *s;
				api_putstrwin(win + 1, x, y, col, 1, t);
			}
		}
		s++;
		x += 8;
	}
	api_refreshwin(win, x0, y, x, y + 16);
	return;
}

void putstr_def(int win, int *winbuf, int x, int y, int col, unsigned char *s)
{
	x = x * 8 + 8;
	y = y * 16 + 29;
	
	api_putstrwin(win, x, y, col, strlen((char *)s), s);
}

void wait(int i, int timer, char *keyflag)
{
	int j;
	if (i > 0) {
		/* 一定時間待つ */
		api_settimer(timer, i);
		i = 128;
	} else {
		i = 0x0a; /* Enter */
	}
	for (;;) {
		j = api_getkey(1);
		if (i == j) {
			break;
		}
		if (j == '4' || j == CUR_LEFT) {
			keyflag[0 /* left */]  = 1;
		}
		if (j == '6' || j == CUR_RIGHT) {
			keyflag[1 /* right */] = 1;
		}
		if (j == ' ') {
			keyflag[2 /* space */] = 1;
		}
	}
	return;
}

void setdec8(char *s, int i)
/* iを10進数表記でsに格納 */
{
	int j;
	for (j = 7; j >= 0; j--) {
		s[j] = '0' + i % 10;
		i /= 10;
	}
	s[8] = 0;
	return;
}
