////////////////////////////////////////////////////////////////////////////////
//  CQ出版社 インターフェース 2008年7月号
//
//  初音ミク（はちゅねみく）・アニメーション
//  FRマイコン用プログラム	Copyright(c)2008 Sumio Morioka
//  morioka@fb3.so-net.ne.jp,  http://www002.upp.so-net.ne.jp/morioka/
//
//  本プログラムコードの商業利用，および改変ファイルの二次配布を禁じます．それ以外の
//  利用はとくに制限しませんが，利用によって生じた被害・不利益などに対しては，一切
//  責任を負いませんのでご了承ください．
//
//  また，本プログラムのサンプルとして同梱される初音ミク，はちゅねミク，鏡音リン・レンの
//  画像（フォント・データも含む）は，クリプトン・フューチャー・メディア株式会社
// （http://www.crypton.co.jp）の著作物です．商業利用等については同社へ問い合わせてください．
//
//
// History:
// 1. Original coding by Sumio Morioka, 2008/04/15
//
////////////////////////////////////////////////////////////////////////////////

#include "_fr.h"


#define	STATE_SET_SPEED		0
#define	STATE_SET_PIC0		1
#define	STATE_WAIT_PIC0		2
#define	STATE_SET_PIC1		3
#define	STATE_WAIT_PIC1		4
#define	STATE_SET_PIC2		5
#define	STATE_WAIT_PIC2		6
#define	STATE_SET_PIC3		7
#define	STATE_WAIT_PIC3		8
#define	STATE_SET_PIC4		9
#define	STATE_WAIT_PIC4		10
#define	STATE_SET_PIC5		11
#define	STATE_WAIT_PIC5		12
#define	STATE_WAIT_FINAL	13

typedef struct _hatyune_state {
	int		xpos;
	int		ypos;
	int		main_state;
	int		times_count;
	int		speed;
	int		vsync_timer;
} HATYUNE_STATE;

#define	HATYUNE_NUM	8


void cls(void)
{
	int	x, y;
	for (y = 0; y < 16; y++) {
		for (x = 0; x < 42; x++) {
			set_cursor(x, y);
			IO_OSDC.IO_OSD_CD1.hword=0x0800;	/* 属性設定 */
			IO_OSDC.IO_OSD_CD2.hword=0x46FC;	/* 文字コード */
		}
	}
}


void font_disp(int start_id, int xpos, int ypos, int xsize, int ysize)
{
	int code;
	int	x, y;

	for (y = 0; y < ysize; y++) {
		code	= 0x4000 + start_id * 4 + (xsize * 4) * y;
		for (x = 0; x < xsize; x++) {
			if (x + xpos < 42 && y + ypos < 16) {
				set_cursor(x + xpos, y + ypos);
				IO_OSDC.IO_OSD_CD1.hword=0x0800;	/* 属性設定 */
				IO_OSDC.IO_OSD_CD2.hword=code;		/* 文字コード */
				code	+= 4;
			}
		}
	}

	v_wait(1);
}


void change_hatyune_state(HATYUNE_STATE *st)
{
	int		rnd;

	switch (st->main_state) {
	case STATE_SET_SPEED:
			rnd	= rand() % 5;
			switch (rnd) {
			case 0:		st->speed	= 6;	break;
			case 1:		st->speed	= 4;	break;
			case 2:		st->speed	= 2;	break;
			case 3:		st->speed	= 1;	break;
			default:	st->speed	= 0;	break;
			}
			st->times_count	= 32 / (st->speed + 1);
			st->main_state	= STATE_SET_PIC0;
			break;

	case STATE_SET_PIC0:
			font_disp(0, st->xpos, st->ypos, 11, 7);
			st->vsync_timer	= st->speed - 1;
			if (st->speed == 0)
				st->main_state	= STATE_SET_PIC2;
			else if (st->speed == 1)
				st->main_state	= STATE_SET_PIC1;
			else
				st->main_state	= STATE_WAIT_PIC0;
			break;

	case STATE_WAIT_PIC0:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0)
				st->main_state	= STATE_SET_PIC1;
			break;

	case STATE_SET_PIC1:
			font_disp(77, st->xpos, st->ypos, 7, 7);
			st->vsync_timer	= st->speed - 1;
			if (st->speed == 1)
				st->main_state	= STATE_SET_PIC2;
			else
				st->main_state	= STATE_WAIT_PIC1;
			break;

	case STATE_WAIT_PIC1:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0)
				st->main_state	= STATE_SET_PIC2;
			break;

	case STATE_SET_PIC2:
			font_disp(126, st->xpos, st->ypos, 7, 7);
			st->vsync_timer	= st->speed - 1;
			if (st->speed == 0) {
				(st->times_count)--;
				if (st->times_count <= 0) {
					st->vsync_timer	= (rand() % 60);
					st->main_state	= STATE_WAIT_FINAL;
				}
				else
					st->main_state	= STATE_SET_PIC0;
			}
			else if (st->speed == 1)
				st->main_state	= STATE_SET_PIC3;
			else
				st->main_state	= STATE_WAIT_PIC2;
			break;

	case STATE_WAIT_PIC2:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0)
				st->main_state	= STATE_SET_PIC3;
			break;

	case STATE_SET_PIC3:
			font_disp(175, st->xpos, st->ypos, 7, 7);
			st->vsync_timer	= st->speed - 1;
			if (st->speed == 1)
				st->main_state	= STATE_SET_PIC4;
			else
				st->main_state	= STATE_WAIT_PIC3;
			break;

	case STATE_WAIT_PIC3:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0)
				st->main_state	= STATE_SET_PIC4;
			break;

	case STATE_SET_PIC4:
			font_disp(224, st->xpos, st->ypos, 7, 7);
			st->vsync_timer	= st->speed - 1;
			if (st->speed == 1)
				st->main_state	= STATE_SET_PIC5;
			else
				st->main_state	= STATE_WAIT_PIC4;
			break;

	case STATE_WAIT_PIC4:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0)
				st->main_state	= STATE_SET_PIC5;
			break;

	case STATE_SET_PIC5:
			font_disp(273, st->xpos, st->ypos, 7, 7);
			st->vsync_timer	= st->speed - 1;
			st->main_state	= STATE_WAIT_PIC5;
			break;

	case STATE_WAIT_PIC5:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0) {
				(st->times_count)--;
				if (st->times_count <= 0) {
					st->vsync_timer	= (rand() % 60);
					st->main_state	= STATE_WAIT_FINAL;
				}
				else
					st->main_state	= STATE_SET_PIC0;
			}
			break;

	case STATE_WAIT_FINAL:
			(st->vsync_timer)--;
			if (st->vsync_timer <= 0)
				st->main_state	= STATE_SET_SPEED;

	default:
		st->main_state	= STATE_SET_SPEED;
	}
}


void main()
{
	HATYUNE_STATE	miku[HATYUNE_NUM];
	int				i;

	__set_il(0x1F); /* ILM = 31 */
	__EI(); 		/* Interrupt enable */

	ppg_init(); 	/* PPG初期化関数 */
	osdc_init(); 	/* OSD初期化関数 */

	srand();
	cls();

	// init state
	for (i = 0; i < HATYUNE_NUM; i++) {
		(miku[i]).xpos			= (i / 2) * 11;
		(miku[i]).ypos			= (i % 2 == 0) ? 0 : 7;
		(miku[i]).main_state	= STATE_SET_SPEED;
	}

	while(1){
		for (i = 0; i < HATYUNE_NUM; i++)
			change_miku_state(&(miku[i]));		// update state
		v_wait(1);								// wait vsync
	}
}

