#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <egb.h>
#include <mos.h>
#include <snd.h>
#include <concorde.h>
#include <tornado.h>
#include <ysmaze2.h>

#pragma On(Align_all_labels)
#pragma On(Align_labels)


#define YES          1
#define NO           0
#define MX          32
#define MY          24
#define EVT_NONE     0
#define EVT_PRESS    1
#define EVT_RELEASE  2

char egb[EgbWorkSize];
char mos[MosWorkSize];
char snd[16*1024];

PAGE *wp,vp[2];
void InitSwapPage();
void ClearSwapPage();
void SwapPage();
void DuplicatePage();
static void InitEgb();
static void InitSnd();
static void InitMos();
static void PrintText(char *tx[]);
void PrintEgb(int x,int y,char *mes,int col);
int GetButtonEvent();
int SystemMenu(char *mn[]);
static void DrawMouseCursor();
void PlayGame(MAZESCREEN *ms,MAZEMAP *mz);
void Radar(MAZEMAP *mz,int rx1,int ry1,int rx2,int ry2,int mx,int my,int l);
int LoadMaze(char *fname,MAZEMAP *mz,short *dat);
void Turn(int *dir,int ofset);
void Progress(MAZEMAP *mz,int *x,int *y,int dir,int v);
int FileSize(FILE *fp);




void main(int argc,char *argv[])
{
	int fin=0,lf=0,sel;
	char *intro[]={"仚仚仚 3師尦柪楬 仚仚仚   by YS-11",
	               "偙偺僾儘僌儔儉偼僷僢僪偺傒偱憖嶌偟",
	               "傑偡丅堦斣嵍忋偐傜僗僞乕僩偟傑偡偺",
	               "偱丄堦斣塃壓偵扝傝拝偄偰偔偩偝偄丅",
	               NULL};
	char *menu[]={"PLAY GAME","EXIT TO TOWNS-OS",NULL};
	short dat[ MX*MY+1 ];
	MAZEMAP mz;
	MAZESCREEN ms={80,60, 0,0,160,120,
	               24*1024+24*32+24,10*1024+10*32+10,
	               5, 64};

	mz.bl=500;
	mz.bh=500;
	mz.lx=24;
	mz.ly=24;
	mz.map=dat;

	if(argc>=2)
	{
		lf=1;
		if(LoadMaze(argv[1],&mz,dat))
		{
			printf("Load Error\n");
			exit(-1);
		}
	}

	InitEgb();
	InitSnd();
	InitMos();
	InitSwapPage();

	PrintText(intro);
	SwapPage();
	GetButtonEvent();
	while(GetButtonEvent()!=EVT_RELEASE);

	while(fin==0)
	{
		sel=SystemMenu(menu);

		switch(sel)
		{
		case 1:
			YGH_clearPage(wp,0);
			if(lf==0)
			{
				int i;
				for(i=0; i<(mz.lx)*(mz.ly); i++)dat[i]=0;
				MazeCreate(&mz);
			}
			dat[(mz.ly)*(mz.lx)-1] |= 64;
		
			MazeDrawMap(wp,&mz,0,0,0,0,mz.lx-1,mz.ly-1,9);
			SwapPage();
			GetButtonEvent();
			while(GetButtonEvent()!=EVT_RELEASE);

			PlayGame(&ms,&mz);
			break;
		case 2:
			fin=1;
			break;
		}
	}

	MOS_end();
	SND_end();
	EGB_init(egb,EgbWorkSize);
}



static void InitEgb()
{
	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);
}

static void InitSnd()
{
	SND_init(snd);
	SND_elevol_set(1,127,127);
}

static void InitMos()
{
	static char moscur[]={
		1,5,
		0x20,0x00,0x88,0x00,0x20,
		0xff,0xff,0xff,0xff,0xff
	};

	MOS_start(mos,MosWorkSize);
	MOS_resolution(0,10);
	MOS_resolution(1,10);
	MOS_color(0,32767);
	MOS_writePage(0);
	MOS_horizon(0,319);
	MOS_vertical(0,239);
	MOS_type(1,2,2,moscur);
}

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

void ClearSwapPage()
{
	YGH_clearPage(&vp[0],0);
	YGH_clearPage(&vp[1],0);
	return;
}

void SwapPage()
{
	int pg,pr;

	if(wp==&vp[0])
	{
		pr=0;
		pg=1;
		wp=&vp[1];
	}
	else
	{
		pr=1;
		pg=2;
		wp=&vp[0];
	}

	EGB_displayPage(egb,pr,pg);
	return;
}

void DuplicatePage()
{
	if(wp==&vp[0])
	{
		YGH_pageCopy(wp,&vp[1]);
	}
	else
	{
		YGH_pageCopy(wp,&vp[0]);
	}
}

static void PrintText(char *tx[])
{
	int y;

	YGH_clearPage(wp,0);
	for(y=0; tx[y]!=NULL; y++)
	{
		PrintEgb(0,15+y*16,tx[y],32767);
	}
}

void PrintEgb(int x,int y,char *mes,int col)
{
	static struct {
		short x,y,len;
		char mes[80];
	} string;

	EGB_color(egb,0,col);
	string.x=x;
	string.y=y;
	string.len=strlen(mes);
	strcpy(string.mes,mes);
	EGB_writePage(egb,0);
	EGB_sjisString(egb,(char *)&string);
	EGB_writePage(egb,1);
	EGB_sjisString(egb,(char *)&string);
}

int GetButtonEvent()
{
	int ret,pad;
	static int prv=0;

	SND_joy_in_2(0,&pad);
	if     ((prv&48)!=48 && (pad&48)==48)ret=EVT_RELEASE;
	else if((prv&48)==48 && (pad&48)!=48)ret=EVT_PRESS;
	else                                 ret=EVT_NONE;
	prv=pad;
	return ret;
}

int SystemMenu(char *mn[])
{
	int x,y,nmn;
	int pad,now,pre;
	extern char YS11mark[];

	for(nmn=0; mn[nmn]!=NULL; nmn++);
	if(nmn==0)
	{
		return 0;
	}

	pre=1;
	now=0;
	GetButtonEvent();
	while(GetButtonEvent()!=EVT_RELEASE)
	{
		if(pre!=now)
		{
			YGH_clearPage(wp,0);
			for(y=0; y<nmn; y++)
			{
				if(y==now)
				{
					YGH_color(wp,992);
				}
				else
				{
					YGH_color(wp,32767);
				}

				x=160-4*strlen(mn[y]);
				YGH_print8font(wp,x,44+y*160/nmn,mn[y]);
			}

			YGH_put(wp,YS11mark,192,208,255,239);
			DrawMouseCursor();
			SwapPage();

			pre=now;
		}

		SND_joy_in_2(0,&pad);
		if((pad & 1)==0)
		{
			now=(now+nmn-1)%nmn;
			while((pad & 1)==0)SND_joy_in_2(0,&pad);
		}
		else if((pad & 2)==0)
		{
			now=(now+1)%nmn;
			while((pad & 2)==0)SND_joy_in_2(0,&pad);
		}
	}

	return now+1;
}

static void DrawMouseCursor()
{
	int bt,mx,my;
	MOS_rdpos(&bt,&mx,&my);
	YGH_color(wp,32767);
	YGH_pset(wp,mx+2,my  );
	YGH_pset(wp,mx-2,my  );
	YGH_pset(wp,mx  ,my+2);
	YGH_pset(wp,mx  ,my-2);
}

void PlayGame(MAZESCREEN *ms,MAZEMAP *mz)
{
	int i,fin,mx,my,dir,spd,pad;
	MAZEZBUF buf[320];
	int rx0,ry0,rx1,ry1,rl;

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

	rl=(ms->y1 -ms->y0)/mz->ly;
	rx0=ms->x1+1;
	ry0=ms->y0;
	rx1=rx0+rl*mz->lx+1;
	ry1=ry0+rl*mz->ly;

	for(i=0; i<2; i++)
	{
		YGH_clearPage(wp,0);
		YGH_color(wp,32767);
		YGH_filledBox(wp,rx0+1,ry0+1,rx1-1,ry1-1);
		YGH_box(wp,rx0,ry0,rx1,ry1);
		YGH_line(wp,rx1,ry1,rx1-rl,ry1-rl);
		YGH_line(wp,rx1,ry1-rl,rx1-rl,ry1);
		PrintEgb(10,150,"PAD  仾伀仼仺: MOVE",32767);
		PrintEgb(10,166,"     A       : GIVE UP",32767);
		SwapPage();
	}

	fin=0;
	while(fin==0)
	{
		MazeGetLines(buf,mz,ms,mx,my,dir,1500);
		MazeDrawWalls(wp,mz,ms,buf);
		Radar(mz,rx0,ry0,rx1,ry1,mx,my,rl);
		SwapPage();

		pad=255;
		while(pad!=255)SND_joy_in_2(0,&pad);
		while(pad==255)SND_joy_in_2(0,&pad);

		if((pad & 16)==0)fin=1;

		if((pad & 32)==0)spd=2;
		else             spd=1;

		if((pad & 1)==0)Progress(mz,&mx,&my,dir, mz->bl*spd/10);
		if((pad & 2)==0)Progress(mz,&mx,&my,dir,-mz->bl*spd/10);
		if((pad & 4)==0)Turn(&dir, 1024*spd);
		if((pad & 8)==0)Turn(&dir,-1024*spd);

		if(mx/mz->bl==mz->lx-1  &&  my/mz->bl==mz->ly-1)fin=2;
	}

	switch(fin)
	{
	case 1:
		DuplicatePage();
		MazeDrawMap(wp,mz,rx0+1,ry0+1,0,0,mz->lx-1,mz->ly-1,rl);
		PrintEgb(100,48,"Give Up!(^_^)",0x7c00);
		GetButtonEvent();
		while(GetButtonEvent()!=EVT_RELEASE);
		break;
	case 2:
		DuplicatePage();
		PrintEgb(100,48,"Congratulations!!",0x7c00);
		GetButtonEvent();
		while(GetButtonEvent()!=EVT_RELEASE);
		break;
	}
}

void Radar(MAZEMAP *mz,int rx1,int ry1,int rx2,int ry2,int mx,int my,int l)
{
	mx=rx1+(mx/mz->bl)*l;
	my=ry1+(my/mz->bl)*l;

	YGH_viewPort(wp,rx1+1,ry1+1,rx2-1,ry2-1);
	YGH_color(wp,0);
	YGH_filledBox(wp,rx1+1,ry1+1,rx2-1,ry2-1);
	YGH_color(wp,31);
	YGH_filledBox(wp,mx,my,mx+l-2,my+l-2);
	YGH_viewPort(wp,0,0,319,239);
}

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

	fp=fopen(fname,"rb");
	if(fp==NULL)return -1;
	fl=FileSize(fp)-16;
	fread(&mz->bl,4,1,fp);
	fread(&mz->bh,4,1,fp);
	fread(&mz->lx,4,1,fp);
	fread(&mz->ly,4,1,fp);
	fread(dat,1,fl,fp);
	fclose(fp);
	return 0;
}

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=mz->bl * mz->lx;
	int ly=mz->bl * mz->ly;
	int x2,y2,bx,by,bx2,by2;

	vx=-MulSin(v,dir);
	vy=-MulCos(v,dir);

	bx= *x/(mz->bl);
	by= *y/(mz->bl);

	x2= *x+vx;
	while(x2<  0)x2+=lx;
	while(x2>=lx)x2-=lx;
	bx2= x2/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;

	y2= *y+vy;
	while(y2<  0)y2+=ly;
	while(y2>=ly)y2-=ly;
	by2= y2/mz->bl;
	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;
}

int FileSize(FILE *fp)
{
    int fptr,edptr;

    fptr = ftell(fp);
    fseek(fp,0,SEEK_END);
    edptr = ftell(fp);
    fseek(fp,fptr,SEEK_SET);
    return edptr;
}
