#include <GConsoleLib.h>
#include <stdio.h>

//マップデータ
#define MAXWIDTH 10
#define MAXHEIGHT 7
int g_mapdata[MAXHEIGHT][MAXWIDTH] = {
	//0  1  2  3  4  5  6  7  8  9
	{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, //0
	{ 1, 0, 0, 1, 2, 0, 0, 1, 3, 1 }, //1
	{ 1, 1, 0, 1, 1, 1, 0, 1, 0, 1 }, //2
	{ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 }, //3
	{ 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 }, //4
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, //5
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }  //6
};

//マップの部品の画像
const char* g_images[] = {
	"C:\\GConsole追加ファイル\\sampleimg\\chap5-1-field.png",
	"C:\\GConsole追加ファイル\\sampleimg\\chap5-1-wall.png",
	"C:\\GConsole追加ファイル\\sampleimg\\chap5-1-goal.png",
	"C:\\GConsole追加ファイル\\sampleimg\\chap5-1-key.png",
	"C:\\GConsole追加ファイル\\sampleimg\\chap5-1-man.png"
};

//主人公の位置
int g_x = 1, g_y = 0;
int g_keyfrag = 0;	//鍵を拾ったフラグ

//画面座標
int g_scx=0, g_scy=0;
#define SCROLLWIDTH 5
#define SCROLLHEIGHT 5
#define CORNERX 165
#define CORNERY 62

//関数プロトタイプ宣言
void DrawMap();
void RedrawMap(int, int, int, int);
int ScrollCheck(int, int);

int main() {
	gcls();
	gfront();

	DrawMap();	//マップ全体を表示

	while (1) {
		glocate(0, 19); gcolor(128, 0, 0);
		gprintf("コマンド（左A、上W、下S、右D）？　　");
		glocate(32, 19);
		char ch = ggetchar();
		int newx=g_x, newy=g_y;
		switch (ch) {
			case 'W':
			case 'w':
				newy--;
				break;
			case 'S':
			case 's':
				newy++;
				break;
			case 'A':
			case 'a':
				newx--;
				break;
			case 'D':
			case 'd':
				newx++;
				break;
		}
		//移動チェック
		if (newx >= 0 && newx < MAXWIDTH && newy >= 0 && newy < MAXHEIGHT){
			//壁かどうかチェック
			if (g_mapdata[newy][newx]!=1){
				//ゴールと鍵の処理
				switch (g_mapdata[newy][newx]){
				case 3://鍵
					g_keyfrag = 1;		//鍵フラグオン
					g_mapdata[newy][newx] = 0;	//鍵を消す
					break;
				case 2:	//ゴール
					if (g_keyfrag) goto GAMECLEAR;
					break;
				}
				int oldx = g_x;
				int oldy = g_y;
				g_x = newx;
				g_y = newy;
				//ScrollCheck関数はスクロールの必要があれば1、
				//不要なら0を返す
				if (ScrollCheck(newx, newy)){
					DrawMap();	//全画面書き換え
				} else {
					RedrawMap(oldx, oldy, newx, newy);	//一部書き換え
				}
			}
		}
	}
	//ゲーム終了
GAMECLEAR:
	const char* ending[] = {
		"君はついにゴールにたどり着いた",
		"しかし本当に冒険は終わったのだろうか……？",
		"",
		"　　　　　　　　　END?"
	};
	gcls();
	gcolor(0, 0, 0);
	gbox(0, 0, 640, 480);
	gcolor(255, 255, 255);
	for (int i = 0; i < 4; i++){
		glocate(12, 16 + i);
		gprintf(ending[i]);
	}
	//スクロール
	for (int i = 0; i<90; i++){
		gprintf("　　　");
	}
}
//マップ再描画（一部のみ）
void RedrawMap(int oldx, int oldy, int newx, int newy) {
	int mapd = g_mapdata[oldy][oldx];
	gimage(g_images[mapd],
		(oldx-g_scx)*62 + CORNERX, (oldy-g_scy)*62 + CORNERY);
	gimage(g_images[4],
		(newx-g_scx)*62 + CORNERX, (newy-g_scy)*62 + CORNERY);
}

//マップ表示
void DrawMap() {
	for (int y=0; y<SCROLLHEIGHT; y++) {
		for (int x=0; x<SCROLLWIDTH; x++) {
			if(x+g_scx == g_x && y+g_scy == g_y){
				//主人公表示
				gimage(g_images[4],
					(g_x-g_scx)*62 + CORNERX, (g_y-g_scy)*62 + CORNERY);
			} else {
				int mapd = g_mapdata[y+g_scy][x+g_scx];
				gimage(g_images[mapd],
					x*62 + CORNERX, y*62 + CORNERY);
			}
		}
	}
}

//スクロールが必要かチェックする関数
//引数には移動先の座標を指定
int ScrollCheck(int newx, int newy) {
	//現在の表示範囲から飛び出しているかをチェック
	//注：座標がg_mapdataの範囲内にあることはチェック済み
	if ( newx < g_scx || newy < g_scy ||
		 newx > g_scx + SCROLLWIDTH - 1 ||
		 newy > g_scy + SCROLLHEIGHT - 1)
	{
		g_scx = newx / SCROLLWIDTH * SCROLLWIDTH;
		if(g_scx + SCROLLWIDTH > MAXWIDTH) {
			g_scx = MAXWIDTH - SCROLLWIDTH;
		}
		g_scy = newy / SCROLLHEIGHT * SCROLLHEIGHT;
		if(g_scy + SCROLLHEIGHT > MAXHEIGHT) {
			g_scy = MAXHEIGHT - SCROLLHEIGHT;
		}
		return 1;//真
	}
	return 0;//偽
}