/*	move.c for PUZZ		Martin Round.	January 1990	*/

unsigned char work  [MAXACROSS] [MAXDOWN];
int scorex,scorey,scoreapen,scorebpen;

extern char line[MAXLINE];
extern int sqrsacross,sqrsdown;
extern unsigned char goal  [MAXACROSS] [MAXDOWN];
extern unsigned char grid	[MAXACROSS] [MAXDOWN];
extern unsigned char movelist [MAXPIECES] [4];

extern int topleftx,toplefty;
extern int sqrwidth,sqrheight;
extern int slide;

extern int moves;
extern int dmapwidth,dmapheight;
extern int audio;

extern struct RastPort *dbuff;

extern void play_note(int,int);

void off ()			/*	turn off any sounds currently playing	*/
	{
	if (audio)
		{
		play_note (100,0);
		play_note (100,1);
		play_note (100,2);
		play_note (100,3);
		}
	}

void tune()
	{
	if (audio)
		{
		off();
		play_note (48,0);
		play_note (48,1);
		Delay (16);
		off();
		Delay (8);
		play_note (43,2);
		Delay (8);
		play_note (42,3);
		play_note (100,2);
		Delay (8);
		play_note (43,2);
		play_note (100,3);
		Delay (8);
		play_note (45,3);
		play_note (100,2);
		Delay (24);
		play_note (43,2);
		play_note (100,3);
		Delay (24);
		off();
		Delay (16);
		play_note (47,0);
		play_note (47,1);
		Delay (16);
		off();
		Delay (16);
		play_note (48,0);
		play_note (48,1);
		play_note (52,2);
		play_note (52,3);
		Delay (16);
		off();
		}
	}

void movesquare(rp,x,y,width,height,dx,dy)
struct RastPort *rp;
int x,y,width,height,dx,dy;
	{
	ClipBlit
			(
			rp,topleftx + x,toplefty + y, 	/* source posn  */
			dbuff,x+dx,y+dy,				/* dest posn	*/
			width,height,					/* size 		*/
			0xc0							/* direct copy  */
			);
	}

int canmove(int piece, int direction)	/*	returns 0 if it can't	*/
	{
	int i,j,old;
	
	for (j=0; j<sqrsdown; j++)
		for (i=0; i<sqrsacross; i++)
			if (piece == grid [i] [j])
				{
				switch (direction)
					{
					case 1:
						if (i == (sqrsacross - 1))	return(0);
						old = grid [i+1] [j];
						break;
					case 2:
						if (j == 0)	return(0);
						old = grid [i] [j-1];
						break;
					case 3:
						if (i == 0)	return(0);
						old = grid [i-1] [j];
						break;
					default:
						if (j == (sqrsdown - 1))	return(0);
						old = grid [i] [j+1];
						break;
					}
				
				if (old && (old != piece))	return (0);
				}
	return (1);
	}

void sortlist (int piece, int move)
	{
	int i;
	
	if ((move+=2) > 4) move -=4;	/*	opposite direction of move	*/
	
	for (i=0; i<3; i++)
		if (move == movelist [piece] [i])
			{
			while (i < 3)
				{
				movelist [piece] [i] = movelist [piece] [i+1];
				i++;
				}
			movelist [piece] [3] = move;	/*	last in new list	*/
			return;
			}
	}
	
int suggestmove(int piece)	/*	1 left, 2 up, 3 right, 4 down, 0 can't	*/
	{
	int i,move;
	
	for (i=0; i<4; i++)		/*	look through move list	*/
		{
		if (canmove(piece,(move = movelist [piece] [i])))
			{
			sortlist (piece,move);
			return (move);
			}
		}
	
	return (0);
	}
	
void moveonepiece(struct RastPort *rp,int piece,int direction)
	{
	int i,j,finished;
	/*	prepare double buffer	*/
	ClipBlit
		(
		rp,topleftx,toplefty, 	/* source posn  */
		dbuff,0,0,				/* dest posn	*/
		dmapwidth,dmapheight,	/* size 		*/
		0xc0					/* direct copy  */
		);

	for (j=0; j<sqrsdown; j++)
		for (i=0; i<sqrsacross; i++)
			if((work [i] [j] = grid [i] [j]) == piece)
				{
				work [i] [j] = 0;
				SetDrMd(dbuff,JAM1);
				SetAPen(dbuff,0);
				RectFill
					(
					dbuff,
					i*sqrwidth,
					j*sqrheight,
					i*sqrwidth+sqrwidth-1,
					j*sqrheight+sqrheight-1
					);
				}
	
	for (j=0; j<sqrsdown; j++)
		{
		for (i=0; i<sqrsacross; i++)
			{
			if (piece == grid [i] [j])
				{
				switch (direction)
					{
					case 1:
						work [i+1] [j] = piece;
						movesquare
							(
							rp,
							i*sqrwidth,
							j*sqrheight,
							sqrwidth,
							sqrheight,
							sqrwidth,
							0
							);
						break;
						
					case 2:
						work [i] [j-1] = piece;
						movesquare
							(
							rp,
							i*sqrwidth,
							j*sqrheight,
							sqrwidth,
							sqrheight,
							0,
							-sqrheight
							);
						break;
						
					case 3:
						work [i-1] [j] = piece;
						movesquare
							(
							rp,
							i*sqrwidth,
							j*sqrheight,
							sqrwidth,
							sqrheight,
							-sqrwidth,
							0
							);
						break;
						
					case 4:
						work [i] [j+1] = piece;
						movesquare
							(
							rp,
							i*sqrwidth,
							j*sqrheight,
							sqrwidth,
							sqrheight,
							0,
							sqrheight
							);
						break;
					}
				}
			}
		}

	ClipBlit
		(
		dbuff,0,0,				/* source posn	*/
		rp,topleftx,toplefty, 	/* dest posn	*/
		dmapwidth,dmapheight,	/* size 		*/
		0xc0					/* direct copy  */
		);
	
	for (j=0; j<sqrsdown; j++)
		for (i=0; i<sqrsacross; i++)
			grid [i] [j] = work [i] [j];
			
	finished = 1;
			
	for (j=0; finished && j<sqrsdown; j++)
		for (i=0; i<sqrsacross; i++)
			if (goal [i] [j] && (grid [i] [j] != goal [i] [j]))
				finished = 0;
	
	if (finished)
		tune();
	}

void updatescore(struct RastPort *rp)
	{
	if (audio)
		play_note (48,0);

	moves++;

	if (scorex || scorey)
		{
		Move(rp,scorex,scorey+6);
		SetDrMd(rp,JAM2);
		SetAPen(rp,scoreapen);
		SetBPen(rp,scorebpen);
		sprintf(line,"Moves:%5d",moves);
		Text(rp,line,11);
		}
	}

int movepiece(struct RastPort *rp,int piece)
	{
	int direction;
	
	if ((direction = suggestmove(piece)) != 0)
		{
		updatescore(rp);
			
		do
			{
			moveonepiece(rp,piece,direction);
			} while (slide && canmove(piece,direction));
		}
	return (direction);
	}

void slidepieces(struct RastPort *rp,int piece)
	{
	int i,j,x,y,zx,zy,direction;
	
	int flag = 1;
	
	for (j=0; flag && j<sqrsdown; j++)
		for (i=0; flag && i<sqrsacross; i++)
			if (piece == grid [i] [j])
				{
				x = i;
				y = j;
				flag = 0;
				}
	
	for (i=0; i<sqrsacross; i++)
		if (grid [i] [y] == 0)
			{
			flag = 1;
			zx = i;
			zy = y;
			}
	
	if (flag == 0)
		for(i=0; i<sqrsdown; i++)
			if (grid [x] [i] == 0)
				{
				flag = 1;
				zx = x;
				zy = i;
				}
	
	if (flag == 0) return;

	if (x == zx)
		{
		if (y > zy)
			{
			for (i=zy+1; i<y; i++)
				if (255 == grid [x] [i])
					return;
			direction = 2;
			}
		else
			{
			for (i=y+1; i<zy; i++)
				if (255 == grid [x] [i])
					return;
			direction = 4;
			}
		}
	else
		{
		if (x > zx)
			{
			for (i=zx+1; i<x; i++)
				if (255 == grid [i] [y])
					return;
			direction = 3;
			}
		else
			{
			for (i=x+1; i<zx; i++)
				if (255 == grid [i] [y])
					return;
			direction = 1;
			}
		}
	
	piece = 0;

	if (x == zx)
		{
		if (y > zy)
			{
			for (i=zy+1; i<=y; i++)
				if ((grid [x] [i]) && (piece != grid [x] [i]))
					{
					if (canmove(piece = grid [x] [i],direction))
						{
						if (flag)
							{
							flag = 0;
							updatescore(rp);
							}
						moveonepiece(rp,piece,direction);
						}
					else return;
					}
			}
		else
			{
			for (i=zy-1; i>=y; i--)
				if ((grid [x] [i]) && (piece != grid [x] [i]))
					{
					if (canmove(piece = grid [x] [i],direction))
						{
						if (flag)
							{
							flag = 0;
							updatescore(rp);
							}
						moveonepiece(rp,piece,direction);
						}
					else return;
					}
			}
		}
	else
		{
		if (x > zx)
			{
			for (i=zx+1; i<=x; i++)
				if ((grid [i] [y]) && (piece != grid [i] [y]))
					{
					if (canmove(piece = grid [i] [y],direction))
						{
						if (flag)
							{
							flag = 0;
							updatescore(rp);
							}
						moveonepiece(rp,piece,direction);
						}
					else return;
					}
			}
		else
			{
			for (i=zx-1; i>=x; i--)
				if ((grid [i] [y]) && (piece != grid [i] [y]))
					{
					if (canmove(piece = grid [i] [y],direction))
						{
						if (flag)
							{
							flag = 0;
							updatescore(rp);
							}
						moveonepiece(rp,piece,direction);
						}
					else return;
					}
			}
		}
	}

void clicked(struct RastPort *rp,int xclick,int yclick)
	{
	int x,y,piece;
	if ((xclick<topleftx) || (yclick<toplefty)) return;
	if ((x = ((xclick-topleftx)/sqrwidth))  >= sqrsacross) return;
	if ((y = ((yclick-toplefty)/sqrheight)) >= sqrsdown)   return;
	if ((piece = grid [x] [y]) == 0) return;
	if (piece == 255) return;
	
	if (slide == 2)
		{
		if (movepiece(rp,piece) == 0)
			slidepieces(rp,piece);
		}
	else
		movepiece(rp,piece);

	if (audio)
		play_note(100,0);

	}
