#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <egb.h>
#include <snd.h>

#include "concorde.h"
#include "tornado.h"
#include "ysmaze2.h"

#define YES          1
#define NO           0
#define MALLOCFUNC  malloc
#define FREEFUNC    free

char egb[EgbWorkSize];
PAGE *wp,vp[2];

int  main(int argc,char *argv[]);
void InitBios();
void InitSwapPage();
void SwapPage();
int  LoadMaze(char *fname,MAZEMAP *mz);
void Turn(int *dir,int ofset);
void Progress(MAZEMAP *mz,int *x,int *y,int dir,int v);
void MazeMain(MAZESCREEN *ms,MAZEMAP *mz);

int main(int argc,char *argv[])
{
	MAZEMAP mz;
	MAZESCREEN ms;

	if(argc<2)
	{
		printf("迷路ファイルを指定してください.\n");
		printf("run386 mazewalk ????.maz\n");
		return 1;
	}

	ms.cx=160;     /* 迷路表示の中心座標 */
	ms.cy=120;

	ms.x0=0;      /* 画面描画範囲 */
	ms.y0=0;
	ms.x1=319;
	ms.y1=239;

	ms.wc=25368;  /* 壁の色(グレー [明]) */
	ms.dc=10570;  /* ドアの色(グレー [暗]) */
	ms.cont=5;    /* 距離に対する輝度の減衰率 */
	ms.mag=64;    /* 拡大率(1m前方の1mの棒が見えるドット数) */

	if(LoadMaze(argv[1],&mz)!=YES)
	{
		printf("迷路 Load Error\n");
		exit(1);
	}

	InitBios();
	InitSwapPage();
	MazeMain(&ms,&mz);
}

void InitBios()
{
	EGB_init(egb,EgbWorkSize);

	EGB_writePage(egb,0);
	EGB_color(egb,1,0);
	EGB_clearScreen(egb);
	EGB_writePage(egb,1);
	EGB_color(egb,1,0);
	EGB_clearScreen(egb);

	EGB_resolution(egb,0,10);
	EGB_resolution(egb,1,10);

	EGB_writePage(egb,0);
	EGB_displayStart(egb,0,0,0);
	EGB_displayStart(egb,2,2,2);
	EGB_displayStart(egb,3,320,240);
	EGB_color(egb,1,0x8000);
	EGB_clearScreen(egb);

	EGB_writePage(egb,1);
	EGB_displayStart(egb,0,0,0);
	EGB_displayStart(egb,2,2,2);
	EGB_displayStart(egb,3,320,240);
	EGB_color(egb,1,0x8000);
	EGB_clearScreen(egb);

	EGB_displayPage(egb,0,3);

	SND_elevol_init();
	SND_elevol_set(1,127,127);
}

void InitSwapPage()
{
	YGH_initPage(&vp[0],SEG_VRAMP,0x00000,512,240);
	YGH_initPage(&vp[1],SEG_VRAMP,0x40000,512,240);
	wp=&vp[0];
	YGH_clearPage(wp,0);
	SwapPage();
	YGH_clearPage(wp,0);
	SwapPage();
}

void SwapPage()
{
	if(wp==&vp[0])
	{
		EGB_displayPage(egb,0,1);
		wp=&vp[1];
	}
	else
	{
		EGB_displayPage(egb,1,2);
		wp=&vp[0];
	}
}

int LoadMaze(char *fname,MAZEMAP *mz)
{
	int siz;
	FILE *fp;
	short *dat;

	if((fp=fopen(fname,"rb"))==NULL)
	{
		return NO;
	}

	fread(&mz->bl,4,1,fp);  /* 1ブロックの壁の長さ (cm) */
	fread(&mz->bh,4,1,fp);  /* 壁の高さ(cm) */
	fread(&mz->lx,4,1,fp);  /* 迷路の横ブロック数 */
	fread(&mz->ly,4,1,fp);  /* 迷路の縦ブロック数 */

	siz=mz->lx*mz->ly;
	if((dat=(short *)MALLOCFUNC(sizeof(short)*siz))==NULL)
	{
		return NO;
	}

	mz->map = dat;          /* 迷路の壁/床/天井データ */
	fread(dat,sizeof(short),siz,fp);

	fclose(fp);
	return YES;
}

void Turn(int *dir,int ofset)
{
	*dir=(*dir+ofset)&65535;
}

void Progress(MAZEMAP *mz,int *x,int *y,int dir,int v)
{
	int vx,vy;
	int lx,ly;
	int x2,y2,bx,by,bx2,by2;

	lx=mz->bl * mz->lx;   /* 迷路全体の横サイズ(cm) */
	ly=mz->bl * mz->ly;   /* 迷路全体の縦サイズ(cm) */

	vx=-MulSin(v,dir);    /* 進もうとするベクトル */
	vy=-MulCos(v,dir);

	bx= *x/(mz->bl);      /* 現在位置(ブロック) */
	by= *y/(mz->bl);

	x2= *x+vx;            /* 移動後の座標(cm)を仮に計算する */
	y2= *y+vy;

	while(x2<  0)x2+=lx;  /* 座標を正規化する */
	while(x2>=lx)x2-=lx;
	while(y2<  0)y2+=ly;
	while(y2>=ly)y2-=ly;

	bx2= x2/mz->bl;       /* 移動後の座標(ブロック) */
	by2= y2/mz->bl;

	if     (vx>0 && bx2!=bx && MazePass(mz,bx,by,3))return;
	else if(vx<0 && bx2!=bx && MazePass(mz,bx,by,1))return;
	else bx=bx2;

	if     (vy>0 && by2!=by && MazePass(mz,bx,by,2))return;
	else if(vy<0 && by2!=by && MazePass(mz,bx,by,0))return;

	*x=x2;
	*y=y2;
}

void MazeMain(MAZESCREEN *ms,MAZEMAP *mz)
{
	int mx,my,dir,pad;
	MAZEZBUF buf[320];

	mx=mz->bl /2;
	my=mz->bl /2;
	dir=49152;

	pad=255;
	while((pad & 16)!=0)  /* Aボタンを押すまでまわる */
	{
		MazeGetLines(buf,mz,ms,mx,my,dir,1500);
		MazeDrawWalls(wp,mz,ms,buf);
		SwapPage();

		SND_joy_in_2(0,&pad);
		if((pad & 1)==0)Progress(mz,&mx,&my,dir, mz->bl/5);
		if((pad & 2)==0)Progress(mz,&mx,&my,dir,-mz->bl/5);
		if((pad & 4)==0)Turn(&dir, 2048);
		if((pad & 8)==0)Turn(&dir,-2048);
	}
}
