/*************************************************
		CNLink  (Ver.1.00)

		Made By	Takahiro Igi (猪木 貴裕)
		Date	Jan 31 2001

*************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/bios.h>
#include <sys/libwwc.h>
#include "graphic.h"

#define is_sjis1( c ) \
	( ( unsigned char )( c ) >= 0x81 && \
	  ( unsigned char )( c ) <= 0x9F || \
	  ( unsigned char )( c ) >= 0xE0 && \
	  ( unsigned char )( c ) <= 0xFC )

#define SCORE_FILE "/ram0/cnl_score.dat"
#define SCORE_FILE_INFO "CNLinkScore"


void ws_init();       /*モノクロのワンダースワンで起動したときに使用*/
void char_spr_init(); /*キャラクタ、スプライトの初期化*/
void palette_init();  /*パレットの初期化*/
void startup_init();  /*使用するカードを3つの配列に区分けする*/
void exp_cursol(int cus_x, int cus_y);/*カーソルを描画*/
void exp_card(int card_color, int card_number, int x, int y);/*カードを描画*/
void exp_link(int link);/*Link数を描画*/
   /*ゲームオーバーなどで終了処理をする*/
void exit_init(unsigned int link, unsigned int time_min, unsigned int time_sec);
                        
void spriteinit(int spno,int fonno, int w, int h, int pal);/*spriteの設定*/
void spriteset(int x, int y, int w, int h, int no);        /*spriteの表示*/
void drawstring( int screen, int x, int y, unsigned char *string, int adr_reset );


/****** 外部変数 ******/
int card_red[12], card_yel[12], card_grn[12], card_blu[12]; /*カードを描画するための配列*/
int stock[13], box[12], card[5][3], before = -1;            /*リンクシステムで使用する配列*/

unsigned int hiscore;
struct stat statbuf;


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

	int x, y, card_color, card_number; /*画面上にあるカードの位置、色、数字*/
	int cus_x = 0, cus_y = 0; /*画面上にあるカーソルの位置*/
	int i, z, main_loop = 1, bk = 0, k = 0;
	unsigned int link = 0, seigen_time = 150, scorefile;
	unsigned int time = 0, time_min = 0, time_sec = 0;  /*最後に表示する暇つぶし時間に使用*/

	if (wwc_get_hardarch() == HARDARCH_WS) {
		ws_init();
        return 1;
    }

	wwc_set_color_mode(COLOR_MODE_4COLOR);
	lcd_set_color(0x6420, 0xfca8);
	display_control(DCM_SCR1 + DCM_SPR);

	srand((sys_get_tick_count() * 123));

	/* ファイルの存在を確認 */
	if(stat(SCORE_FILE, &statbuf) == E_FS_FILE_NOT_FOUND) {
		  /* なかったら作る(1 ブロックだけ使う) */ 
		  if(creat(SCORE_FILE, FMODE_W|FMODE_R, 1) != E_FS_SUCCESS) { 
			  text_put_string(0, 0, "can't creat score file"); 
			  bios_exit();
		  } 
		/* ファイル情報セット */ 
		 fs_setinfo(SCORE_FILE, SCORE_FILE_INFO);
		 if((scorefile = open(SCORE_FILE, O_RDWR, 0)) < 0) {
			  text_put_string(0, 0, "can't access score file");
			  key_wait();
			  bios_exit();
		  }
		  /* 初期化 */
		  hiscore = 0;
		  write(scorefile, (BYTE far *)&hiscore, sizeof(hiscore));
		  lseek(scorefile, 0, 0);
	}else{
		  /* ファイルがあったらオープン */
		  if((scorefile = open(SCORE_FILE, O_RDWR, 0)) < 0) {
			  text_put_string(0, 0, "can't access score file");
			  key_wait(); 
			  bios_exit();
		  }
	} 
	/* ハイスコア読み込み */
	lseek(scorefile, 0, 0) ;
	read(scorefile, (BYTE far *)&hiscore, sizeof(hiscore)); 


	char_spr_init();/*キャラクタ、スプライトの初期化*/
	palette_init();/*パレット初期化*/

	
	screen_fill_char(SCREEN1,0,0,32,32,0x0000);
	

	startup_init();/*カードの最初の並びをつくる*/

	for(x = 0; x < 5; x++){/*カードの最初の並びを表示*/
		for(y  = 0; y < 3; y++){
			card_color  = card[x][y] / 10; /*0なら赤,1なら黄,2なら緑,3なら青*/
			card_number = card[x][y] % 10;

			exp_card(card_color, card_number, x, y);/*カードを表示*/
		}
	}
	exp_link(link);/*Link数を表示*/
	exp_cursol(cus_x, cus_y);/*カーソルを表示*/

	/*以下の６行を除くと多少支障をきたす*/
	drawstring(SCREEN1,3, 3, "スタートボタンを押すとゲームを開始します",0);
	while(main_loop == 1){
		bk = k;
		k = key_press_check();
		if(((bk & KEY_START) == 0) && (k & KEY_START)){ break;}
	}
	screen_fill_char(SCREEN1,3, 3, 20, 1, 0x0000);

	drawstring(SCREEN1, 1, 4, "TIME",0);
	screen_fill_char(SCREEN1, 6, 4, 20, 1, 0x0043); /*灰色の制限時間スライドバーを表示*/

	
	while(main_loop == 1){	/*このループがメイン*/
		bk = k;
		k = key_press_check();

		if(( (bk & KEY_LEFT1) == 0) && (k & KEY_LEFT1)){
			cus_x--;
			if(cus_x < 0){cus_x = 4;}
		}

		if(( (bk & KEY_RIGHT1) == 0)&& (k & KEY_RIGHT1)){
			cus_x++;
			if(cus_x > 4){cus_x = 0;}
		}

		if(( (bk & KEY_UP1) == 0) && (k & KEY_UP1)){
			cus_y--;
			if(cus_y < 0){cus_y = 2;}
		}

		if(( (bk & KEY_DOWN1) == 0) && (k & KEY_DOWN1)){
			cus_y++;
			if(cus_y >2){cus_y = 0;}
		}

		/*このA,Bボタン時の処理はreadme.txtに書いてあるのでそっちを参考に*/
		if((( (bk & KEY_A) == 0) && (k&KEY_A)) || (( (bk & KEY_B) == 0) && (k&KEY_B)) ){
			if( link == 0 || (((before % 10) == (card[cus_x][cus_y] % 10)) || ((before / 10) == (card[cus_x][cus_y] / 10))) ){
				before = card[cus_x][cus_y];
				z = rand() % 13;
				card[cus_x][cus_y] = stock[z];
				stock[z] = box[0];
				for(i = 0; i <= 10; i++){box[i] = box[i+1];}
				box[11] = before;
				card_color  = card[cus_x][cus_y] / 10;
				card_number = card[cus_x][cus_y] % 10;

				exp_card(card_color, card_number, cus_x, cus_y);

				if(link < 65535){link++;}/*ここでLink数を増やし、タイマーを元に戻す*/
				exp_link(link);
				seigen_time = 150;

				/*以下９行は、選んだカードを左上に表示しておくために使用*/
				card_color  = before / 10;
				card_number = before % 10;

				if(card_color == 0){screen_set_char(SCREEN1, 2, 0, 4, 3, card_red);}
				if(card_color == 1){screen_set_char(SCREEN1, 2, 0, 4, 3, card_yel);}
				if(card_color == 2){screen_set_char(SCREEN1, 2, 0, 4, 3, card_grn);}
				if(card_color == 3){screen_set_char(SCREEN1, 2, 0, 4, 3, card_blu);}

				sprite_set_char(20,1+card_number);
			}
		}

		if(((bk & KEY_UP2) == 0) && (k & KEY_UP2)){/*Y1で強制終了*/
			main_loop = 0;
			break;
		}

		if(((bk & KEY_START) == 0) && (k & KEY_START)){/*ポーズをかける*/
			drawstring(SCREEN1,21, 1, "PAUSE",0);
			while(key_wait() != KEY_START);
			screen_fill_char(SCREEN1,21, 1, 5, 1, 0x0000);
		}
		exp_cursol(cus_x, cus_y);

		time++;
		if(time == 75){time_sec += 1; time = 0;}/*ここでプレイ時間の処理*/
		if(time_sec == 60){time_min += 1; time_sec = 0;}

		seigen_time--; /*ここで制限時間の処理、時間切れで強制終了*/
		spriteset(48 + seigen_time, 32, 1, 1, 41);
		if(seigen_time <= 0){
			main_loop = 0;
			break;
		}

		sys_wait(1);

	}/*ここまでがmain_loopのループ*/

	exit_init(link, time_min, time_sec); /*この先はtextモードになる*/

	lseek(scorefile, 0, 0); 
	write(scorefile, (BYTE far *)&hiscore, sizeof(hiscore));/*hiscore記録*/
	close(scorefile);

}

void char_spr_init()
{
	int i = 1, x, y;

	font_set_colordata(0, 1, bmp_clear);
	font_set_colordata(1, 10,bmp_suuji);
	font_set_colordata(11,12,bmp_card);
	font_set_colordata(23,1, bmp_cus_t);
	font_set_colordata(24,1, bmp_cus_r);
	font_set_colordata(25,1, bmp_cus_d);
	font_set_colordata(26,1, bmp_cus_l);
	font_set_colordata(27,40,bmp_suuji2);
	font_set_colordata(67,1, bmp_bar1);
	font_set_colordata(68,1, bmp_bar2);

	sprite_set_char_location(0,0,0,0);

	for(y = 0; y < 3; y++){     /*ここは画面上の15枚のカードの上にある数字を配置する*/
		for(x = 0; x < 5; x++){ /*実際に数字を入れるのは上のexp_card内の処理*/
			sprite_set_location(i, 28+(x * 40), 56+(y * 32));
			i++;
		}
	}

	sprite_set_char(16, 23);/*上の下矢印カーソル*/
	sprite_set_char(17, 24);/*右の左矢印カーソル*/
	sprite_set_char(18, 25);/*下の上矢印カーソル*/
	sprite_set_char(19, 26);/*左の右矢印カーソル*/

	sprite_set_location(20, 28, 8);/*左上に表示される前のカード用*/
	sprite_set_char(20,0);


	spriteset(72, 0, 2, 2, 21);
	spriteset(88, 0, 2, 2, 25);
	spriteset(104,0, 2, 2, 29);
	spriteset(120,0, 2, 2, 33);
	spriteset(136,0, 2, 2, 37);/*Link数の表示場所を宣言*/

	spriteinit(41, 68, 1, 1, 12);/*制限時間スライドバーで使用、動く黒いつまみ*/
	spriteset(-8,-8, 1, 1, 41);

	sprite_set_range(0,42);
}

void palette_init()
{
	int i = 0;

	wwc_palette_set_color(0, 0, 0x0fff);
	wwc_palette_set_color(0, 1, 0x0aaa);
	wwc_palette_set_color(0, 2, 0x0666);
	wwc_palette_set_color(0, 3, 0x0000);/*モノクロ系統*/

	wwc_palette_set_color(1, 0, 0x0fff);
	wwc_palette_set_color(1, 1, 0x0600);
	wwc_palette_set_color(1, 2, 0x0a00);
	wwc_palette_set_color(1, 3, 0x0f00);/*赤系統*/

	wwc_palette_set_color(2, 0, 0x0fff);
	wwc_palette_set_color(2, 1, 0x0660);
	wwc_palette_set_color(2, 2, 0x0aa0);
	wwc_palette_set_color(2, 3, 0x0ff0);/*黄系統*/

	wwc_palette_set_color(3, 0, 0x0fff);
	wwc_palette_set_color(3, 1, 0x0060);
	wwc_palette_set_color(3, 2, 0x00a0);
	wwc_palette_set_color(3, 3, 0x00f0);/*緑系統*/

	wwc_palette_set_color(4, 0, 0x0fff);
	wwc_palette_set_color(4, 1, 0x0006);
	wwc_palette_set_color(4, 2, 0x000a);
	wwc_palette_set_color(4, 3, 0x000f);/*青系統*/

	wwc_palette_set_color(12, 0, 0x0fff);
	wwc_palette_set_color(12, 1, 0x0fff);
	wwc_palette_set_color(12, 2, 0x0000);
	wwc_palette_set_color(12, 3, 0x0000);/*スプライトで使用*/

	/*bmp_cardを形にするところ、screen_set_charは配列で使用するため*/
	for(i = 0; i < 12; i++){card_red[i] = (11 + i) |  512;}/*1番パレットを使って赤のカードに*/
	for(i = 0; i < 12; i++){card_yel[i] = (11 + i) | 1024;}/*2番パレットを使って黄のカードに*/
	for(i = 0; i < 12; i++){card_grn[i] = (11 + i) | 1536;}/*3番パレットを使って緑のカードに*/
	for(i = 0; i < 12; i++){card_blu[i] = (11 + i) | 2048;}/*4番パレットを使って青のカードに*/

}

void startup_init()
{
	int s = 0, b = 0, cx = 0, cy = 0, no, i;

	for(no = 0; no < 40;){

		i = rand() % 3;

		if(i == 0){             /*配列Stockの初期化、全部で13枚*/
			if(s < 13){
				stock[s] = no;
				s++;
				no++;
			}
		}
		if(i == 1){             /*配列boxの初期化、全部で12枚*/
			if(b < 12){
				box[b] = no;
				b++;
				no++;
			}
		}
		if(i == 2){             /*配列cardの初期化、全部で15枚*/
			if(cy < 3){
				card[cx][cy] = no;
				cx++;
				if(cx > 4){cy++; cx = 0;}
				no++;
			}
		}
	}
}

void ws_init()
{
	text_screen_init();
    text_put_string(3, 4, "このプログラムはカラー専用です");
	text_put_string(3, 6, "WonderSwanColorで実行してください");
	text_put_string(11,16, "2001 沙織交響楽団");
	key_wait();

}

void exp_cursol(int cus_x, int cus_y)
{
	sprite_set_location(16, 28 + cus_x*40, 40 + cus_y*32);
	sprite_set_location(17, 48 + cus_x*40, 56 + cus_y*32);
	sprite_set_location(18, 28 + cus_x*40, 72 + cus_y*32);
	sprite_set_location(19,  8 + cus_x*40, 56 + cus_y*32);/*カーソルの描画*/
}

void exp_card(int card_color, int card_number, int x, int y)
{
	/*main関数から来るcard_colorにしたがって、カードを描画*/
	if(card_color == 0){screen_set_char(SCREEN1, 2 + x*5, 6 + y*4, 4, 3, card_red);}
	if(card_color == 1){screen_set_char(SCREEN1, 2 + x*5, 6 + y*4, 4, 3, card_yel);}
	if(card_color == 2){screen_set_char(SCREEN1, 2 + x*5, 6 + y*4, 4, 3, card_grn);}
	if(card_color == 3){screen_set_char(SCREEN1, 2 + x*5, 6 + y*4, 4, 3, card_blu);}

	/*カード上の数字を描画        12番パレットだから↓ここでパレットを指定*/
	sprite_set_char(1+x + y*5, 1 + (card_number) | 2048);
}

void exp_link(int link)
{
	/*27番キャラクタからLink数だけキャラクタを先送りしてスプライトで描画*/
	if(link <= 65535){
		spriteinit(21,(27+ 4*(link / 10000 % 10)), 2, 2, 12);
		spriteinit(25,(27+ 4*(link / 1000  % 10)), 2, 2, 12);
		spriteinit(29,(27+ 4*(link / 100   % 10)), 2, 2, 12);
		spriteinit(33,(27+ 4*(link / 10    % 10)), 2, 2, 12);
		spriteinit(37,(27+ 4*(link         % 10)), 2, 2, 12);
	}
	else{link--;}

}

void exit_init(unsigned int link, unsigned int time_min, unsigned int time_sec)
{
	/*終了処理　ここからテキストモードになります。*/
	static unsigned char buf[30];

	display_control(DCM_SCR2);
	text_screen_init();

	sprintf(buf, "今回のLink数: %d", link);
	text_put_string(5,4,buf);
	sprintf(buf, "今までの最高Link数: %d", hiscore);
	text_put_string(5,5,buf);

	if(hiscore < link){
		text_put_string(5,7,"新記録達成！記録しておきます。");
		hiscore = link;/*ここでLinkをhiscoreに代入、記録するのはmainの最後だけど*/
	}


	sprintf(buf,"今回の暇つぶし時間: %d分%d秒", time_min, time_sec);
	text_put_string(5,9,buf);

	text_put_string(2,14,"STARTボタンで終了です。お疲れ様でした。");
	text_put_string(5,16,"2001 沙織交響楽団");

	while(key_wait() != KEY_START);

	
    wwc_set_color_mode(COLOR_MODE_GRAYSCALE);
}

void spriteinit(int spno,int fonno, int w, int h, int pal)
{
	int i;
	int attr;

	for ( i=0; i<w*h; i++ ) {
		attr = ((pal-8)*512) | (i+fonno);
		sprite_set_char( spno, attr );
		spno++;
	}
}

void spriteset(int x, int y, int w, int h, int no)
{
	int dx, dy;

	for(dy = 0; dy < h; dy++){
		for(dx = 0; dx < w; dx++){
			sprite_set_location(no, x+dx*8, y+dy*8);
			no++;
		}
	}
}
void drawstring( int screen, int x, int y, unsigned char *string, int adr_reset )
{
	static int count = 0;
	unsigned char fontbuf[8];
	unsigned char bytedata;
	unsigned int  worddata;

	if( adr_reset ){ count = 0; }
	while( 1 ){
		bytedata = *string++;
		if( bytedata != NULL ){
			if( is_sjis1( bytedata ) ){
				/* Shift-JIS Code */
				worddata = bytedata << 8;
				worddata |= *string++;
				text_get_fontdata( worddata, fontbuf );
			}else{
				/* ASCII Code */
				text_get_fontdata( bytedata, fontbuf );
			}
			font_set_monodata(69 + count, 1, fontbuf );
			screen_fill_char( screen, x, y, 1, 1, 69 + count );
			count++;
			x++;
		}else{
			return;
		}
	}
}