//---------------------------------------------------------------------------------------------
#include <stdio.h>
#include <system.h>
#include <io.h>
#include "begin.h"
#include "intermission.h"
#include "chomp.h"
#include "death.h"
#include "fruit.h"
#include "ghost.h"
//---------------------------------------------------------------------------------------------
#define IOWR_VGA(base,offset,data) IOWR_16DIRECT(base,(offset)*2,data)
#define IORD_VGA(base,offset) IORD_16DIRECT(base,(offset)*2)
#define PAC_V 1
#define GHOST_V 1
#define PAC_R 9
#define GHOST_R 9

#define INITIAL_GAME_SPEED 5000
#define TOTAL_PACDOT_NUM 240
#define INITIAL_PACX 14
#define INITIAL_PACY 23
#define INITIAL_GHOST_X 13
#define INITIAL_GHOST_Y 14
#define INITIAL_PAC_LIFE 3
#define PAC_MOUTH_SPEED 21
#define PAC_DIE_TIME 30
#define GHOST_FLOAT_SPEED 20
#define GHOST_WEAK_TIME 600
#define GHOST_BLINK_TIME 30
//---------------------------------------------------------------------------------------------
int gameSpeed = INITIAL_GAME_SPEED;
int pacX = INITIAL_PACX;
int pacY = INITIAL_PACY;
int pacImgX = 203 + 9 * INITIAL_PACX;
int pacImgY = 105 + 9 * INITIAL_PACY;
int pacLife = INITIAL_PAC_LIFE;
int pacMove = 1;
int pacMouth = 0;
int pacDie = 0;
int ghostX[3];
int ghostY[3];
int ghostV[3] = {GHOST_V, GHOST_V, GHOST_V};
int ghostImgX[3];
int ghostImgY[3];
int ghostOption[3][4];
int ghostMove[3];
int ghostOperation[3];
int ghostFloat[] = {0, 0, 0};
int ghostWeakMode[] = {0, 0, 0};
int ghostEaten[] = {0, 0, 0};
int ghostModeSwitchTime[] = {800, 1000, 1200};
int ghostMode[] = {0, 0, 0};
int pacDot = TOTAL_PACDOT_NUM;
int score = 0;
int level = 1;
unsigned char keyBoardCode = 0;
//---------------------------------------------------------------------------------------------
void createPac() {
	pacX = INITIAL_PACX;
	pacY = INITIAL_PACY;
	pacImgX = 203 + 9 * INITIAL_PACX;
	pacImgY = 105 + 9 * INITIAL_PACY;
	pacDie = 0;
	pacMove = 1;
	keyBoardCode = 0;
}
//---------------------------------------------------------------------------------------------
void createGhost() {
	int i;
	for(i = 0; i < 3; i++) {
		ghostX[i] = INITIAL_GHOST_X;
		ghostY[i] = INITIAL_GHOST_Y;
		ghostImgX[i] = 203 + 9 * ghostX[i];
		ghostImgY[i] = 105 + 9 * ghostY[i];
		ghostMove[i] = 1;
		ghostV[i] = GHOST_V;
		ghostWeakMode[i] = 0;
		ghostEaten[i] = 0;
		ghostMode[i] = 0;
	}
}
//---------------------------------------------------------------------------------------------
void initializeStage() {
	IOWR_VGA(VGA_BASE, 14, 0);	//create maze
	if(level < 10) {
		IOWR_VGA(VGA_BASE, 12, 882);	//write level to VGA
		IOWR_VGA(VGA_BASE, 13, 38 + level++);
		if(level > 1)
			gameSpeed -= 250;
	}
	pacDot = TOTAL_PACDOT_NUM;	//initialize game parameters
	createPac();
	createGhost();
}
//---------------------------------------------------------------------------------------------
void paintScore() {
	int scoreDigi[4];
	scoreDigi[0] = score / 1000;
	scoreDigi[1] = (score - scoreDigi[0] * 1000) / 100;
	scoreDigi[2] = (score - scoreDigi[0] *  1000 - scoreDigi[1] * 100) / 10;
	scoreDigi[3] = score - scoreDigi[0] *  1000 - scoreDigi[1] * 100 - scoreDigi[2] *  10;
	int i;
	for(i = 0; i < 4; i++) {
		IOWR_VGA(VGA_BASE, 12, 873 + i);
		IOWR_VGA(VGA_BASE, 13, 38 + scoreDigi[i]);
	}
}
//---------------------------------------------------------------------------------------------
void paintLife() {
	switch(pacLife) {
	case 3:
		IOWR_VGA(VGA_BASE, 12, 883);
		IOWR_VGA(VGA_BASE, 13, 50);
		IOWR_VGA(VGA_BASE, 12, 884);
		IOWR_VGA(VGA_BASE, 13, 50);
		break;
	case 2:
		IOWR_VGA(VGA_BASE, 12, 883);
		IOWR_VGA(VGA_BASE, 13, 28);
		IOWR_VGA(VGA_BASE, 12, 884);
		IOWR_VGA(VGA_BASE, 13, 50);
		break;
	case 1:
		IOWR_VGA(VGA_BASE, 12, 883);
		IOWR_VGA(VGA_BASE, 13, 28);
		IOWR_VGA(VGA_BASE, 12, 884);
		IOWR_VGA(VGA_BASE, 13, 28);
		break;
	default:
		break;
	}
}
//---------------------------------------------------------------------------------------------
void paintPac() {
	IOWR_VGA(VGA_BASE, 0, pacImgX);
	IOWR_VGA(VGA_BASE, 1, pacImgY);
	if(pacDie == 0) {
		if(pacMouth < PAC_MOUTH_SPEED / 3) {
			switch(pacMove) {
			case 1:
				IOWR_VGA(VGA_BASE, 2, 1);
				break;
			case 2:
				IOWR_VGA(VGA_BASE, 2, 3);
				break;
			case 3:
				IOWR_VGA(VGA_BASE, 2, 5);
				break;
			case 4:
				IOWR_VGA(VGA_BASE, 2, 7);
				break;
			default:
				break;
			}
		}
		if(pacMouth < 2 * PAC_MOUTH_SPEED / 3) {
			switch(pacMove) {
			case 1:
				IOWR_VGA(VGA_BASE, 2, 2);
				break;
			case 2:
				IOWR_VGA(VGA_BASE, 2, 4);
				break;
			case 3:
				IOWR_VGA(VGA_BASE, 2, 6);
				break;
			case 4:
				IOWR_VGA(VGA_BASE, 2, 8);
				break;
			default:
				break;
			}
		}
		else
			IOWR_VGA(VGA_BASE, 2, 0);
		pacMouth = (pacMouth + 1) % PAC_MOUTH_SPEED;
	}
	else {
		if(pacDie < PAC_DIE_TIME / 3)
			IOWR_VGA(VGA_BASE, 2, 17);
		else if(pacDie < 2 * PAC_DIE_TIME / 3)
			IOWR_VGA(VGA_BASE, 2, 18);
		else
			IOWR_VGA(VGA_BASE, 2, 19);
		pacDie = (pacDie + 1) % PAC_DIE_TIME;
		if(pacDie == 0) {
			if(pacLife > 0) {
				createPac();
				createGhost();
			}
			else {
				printf("[Game Over]\n");
				printf("[Your Score] %d Press any key to continue...\n", score);
			}
		}
	}

	paintScore();
	paintLife();
}
//---------------------------------------------------------------------------------------------
void paintGhost(int ghostNum) {
	IOWR_VGA(VGA_BASE, 3 + 3 * ghostNum, ghostImgX[ghostNum]);
	IOWR_VGA(VGA_BASE, 4 + 3 * ghostNum, ghostImgY[ghostNum]);
	//ghost is in house
	if(ghostImgX[ghostNum] >= 302 && ghostImgX[ghostNum] <= 306
			&& ghostY[ghostNum] >= 13 && ghostY[ghostNum] <= 15) {
		IOWR_VGA(VGA_BASE, 3 + 3 * ghostNum, 306);
		if(ghostMove[ghostNum] == 3)
			ghostImgX[ghostNum] = 302;
	}
	if(ghostImgX[ghostNum] >= 343 && ghostImgX[ghostNum] <= 347
			&& ghostY[ghostNum] >= 13 && ghostY[ghostNum] <= 15) {
		IOWR_VGA(VGA_BASE, 3 + 3 * ghostNum, 343);
		if(ghostMove[ghostNum] == 1)
			ghostImgX[ghostNum] = 347;
	}
	if(ghostImgY[ghostNum] >= 236 && ghostImgY[ghostNum] <= 240
			&& ghostX[ghostNum] >= 11 && ghostX[ghostNum] <= 16) {
		IOWR_VGA(VGA_BASE, 4 + 3 * ghostNum, 236);
		if(ghostMove[ghostNum] == 2)
			ghostImgY[ghostNum] = 240;
	}
	if(ghostImgY[ghostNum] >= 222 && ghostImgY[ghostNum] <= 227
			&& (ghostX[ghostNum] == 11 || ghostX[ghostNum] == 12
					||	ghostX[ghostNum] == 15 || ghostX[ghostNum] == 16)) {
		IOWR_VGA(VGA_BASE, 4 + 3 * ghostNum, 227);
		if(ghostMove[ghostNum] == 4)
			ghostImgY[ghostNum] = 222;
	}

	if(ghostWeakMode[ghostNum] == 0) {
		if(ghostFloat[ghostNum] < GHOST_FLOAT_SPEED / 2)
			IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 7 + ghostMove[ghostNum] * 2);
		else
			IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 8 + ghostMove[ghostNum] * 2);
	}
	else {
		if(ghostWeakMode[ghostNum] < 3 * GHOST_WEAK_TIME / 4) {
			if(ghostFloat[ghostNum] < GHOST_FLOAT_SPEED / 2)
				IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 24);
			else
				IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 25);
		}
		else
		{
			if(ghostWeakMode[ghostNum] % GHOST_BLINK_TIME < GHOST_BLINK_TIME / 2) {
				if(ghostFloat[ghostNum] < GHOST_FLOAT_SPEED / 2)
					IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 26);
				else
					IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 27);
			}
			else {
				if(ghostFloat[ghostNum] < GHOST_FLOAT_SPEED / 2)
					IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 24);
				else
					IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 25);
			}
		}
		ghostWeakMode[ghostNum] = (ghostWeakMode[ghostNum] + 1) % GHOST_WEAK_TIME;
	}

	if(ghostEaten[ghostNum] == 1) {
		IOWR_VGA(VGA_BASE, 5 + 3 * ghostNum, 19 + ghostMove[ghostNum]);
	}
	ghostFloat[ghostNum] = (ghostFloat[ghostNum] + 1) % GHOST_FLOAT_SPEED;
}
//---------------------------------------------------------------------------------------------
void movePac() {
	if(pacDie == 0) {
		int nextPacX;
		int nextPacY;
		unsigned nextContent;
		switch(keyBoardCode)
		{
		case 116:	//right
			if(pacImgX < 446) {
				nextPacX = (pacImgX + PAC_R - 203) / 9;
				IOWR_VGA(VGA_BASE, 15, pacY * 28 + nextPacX);
				nextContent = IORD_VGA(VGA_BASE, 0);
				if(nextContent == 26 || nextContent == 27 || nextContent == 28) {
					pacImgX += PAC_V;
					pacImgY = pacImgY - (pacImgY - 105) % 9;
					pacMove = 1;
				}
				else if(pacMove != 1) {
					switch(pacMove) {
					case 2:
						keyBoardCode = 114;
						break;
					case 3:
						keyBoardCode = 107;
						break;
					case 4:
						keyBoardCode = 117;
						break;
					}
				}
			} else {
				pacImgX = 203;
			}
			break;
		case 114:	//down
			nextPacY = (pacImgY + PAC_R - 105) / 9;
			IOWR_VGA(VGA_BASE, 15, nextPacY * 28 + pacX);
			nextContent = IORD_VGA(VGA_BASE, 0);
			if(nextContent == 26 || nextContent == 27 || nextContent == 28) {
				pacImgY += PAC_V;
				pacImgX = pacImgX - (pacImgX - 203) % 9;
				pacMove = 2;
			}
			else if(pacMove != 2) {
				switch(pacMove) {
				case 1:
					keyBoardCode = 116;
					break;
				case 3:
					keyBoardCode = 107;
					break;
				case 4:
					keyBoardCode = 117;
					break;
				}
			}
			break;
		case 107:	//left
			if(pacImgX >= 203) {
				nextPacX = (pacImgX - PAC_V - 203) / 9;
				IOWR_VGA(VGA_BASE, 15, pacY * 28 + nextPacX);
				nextContent = IORD_VGA(VGA_BASE, 0);
				if(nextContent == 26 || nextContent == 27 || nextContent == 28) {
					pacImgX -= PAC_V;
					pacImgY = pacImgY - (pacImgY - 105) % 9;
					pacMove = 3;
				}
				else if(pacMove != 3) {
					switch(pacMove) {
					case 1:
						keyBoardCode = 116;
						break;
					case 2:
						keyBoardCode = 114;
						break;
					case 4:
						keyBoardCode = 117;
						break;
					}
				}
			} else {
				pacImgX = 446;
			}
			break;
		case 117:	//up
			nextPacY = (pacImgY - PAC_V - 105) / 9;
			IOWR_VGA(VGA_BASE, 15, nextPacY * 28 + pacX);
			nextContent = IORD_VGA(VGA_BASE, 0);
			if(nextContent == 26 || nextContent == 27 || nextContent == 28) {
				pacImgY -= PAC_V;
				pacImgX = pacImgX - (pacImgX - 203) % 9;
				pacMove = 4;
			}
			else if(pacMove != 4) {
				switch(pacMove) {
				case 1:
					keyBoardCode = 116;
					break;
				case 2:
					keyBoardCode = 114;
					break;
				case 3:
					keyBoardCode = 107;
					break;
				}
			}
			break;
		case 118:	//pause
			printf("[Game Paused] Press any key to continue...\n");
			while(keyBoardCode == 118) {
				while(!IORD_8DIRECT(KEYBOARD_BASE,0));
				keyBoardCode = IORD_8DIRECT(KEYBOARD_BASE,1);
			}
			break;
		default:
			break;
		}

		pacX = (pacImgX - 203) / 9;
		pacY = (pacImgY - 105) / 9;


		unsigned mazeContent;
		IOWR_VGA(VGA_BASE, 15, pacY * 28 + pacX);
		mazeContent = IORD_VGA(VGA_BASE, 0);

		switch(mazeContent) {
		case 26:
			IOWR_VGA(VGA_BASE, 12, pacY * 28 + pacX);
			IOWR_VGA(VGA_BASE, 13, 28);
			pacDot--;
			score += 1;
			break;
		case 27:
			IOWR_VGA(VGA_BASE, 12, pacY * 28 + pacX);
			IOWR_VGA(VGA_BASE, 13, 28);
			int i;
			for(i = 0; i < 3; i++)
				ghostWeakMode[i] = 1;
			score += 10;
			break;
		default:
			break;
		}
	}

	paintPac();
}
//---------------------------------------------------------------------------------------------
int isAvailable(int ghostNum, int direction) {
	int nextX;
	int nextY;
	unsigned nextContent;
	switch(direction) {
	case 1:	//right
		if(ghostImgX[ghostNum] < 446) {
			nextX = (ghostImgX[ghostNum] + GHOST_R - 203) / 9;
			if((ghostImgY[ghostNum] - 105) % 9 == 0) {
				IOWR_VGA(VGA_BASE, 15, ghostY[ghostNum] * 28 + nextX);
				nextContent = IORD_VGA(VGA_BASE, 0);
				if(nextContent == 26 || nextContent == 27 || nextContent == 28
						|| nextContent == 17 || nextContent == 18)
					return 1;
			}
		}
		else
			return 1;
		break;
	case 2:	//down
		nextY = (ghostImgY[ghostNum] + GHOST_R - 105) / 9;
		if((ghostImgX[ghostNum] - 203) % 9 == 0) {
			IOWR_VGA(VGA_BASE, 15, nextY * 28 + ghostX[ghostNum]);
			nextContent = IORD_VGA(VGA_BASE, 0);
			if(nextContent == 26 || nextContent == 27 || nextContent == 28
					|| nextContent == 17 || nextContent == 18)
				return 1;
		}
		break;
	case 3:	//left
		if(ghostImgX[ghostNum] >= 203) {
			nextX = (ghostImgX[ghostNum] - GHOST_V - 203) / 9;
			if((ghostImgY[ghostNum] - 105) % 9 == 0) {
				IOWR_VGA(VGA_BASE, 15, ghostY[ghostNum] * 28 + nextX);
				nextContent = IORD_VGA(VGA_BASE, 0);
				if(nextContent == 26 || nextContent == 27 || nextContent == 28
						|| nextContent == 17 || nextContent == 18)
					return 1;
			}
		}
		else
			return 1;
		break;
	case 4:	//up
		nextY = (ghostImgY[ghostNum] - GHOST_V - 105) / 9;
		if((ghostImgX[ghostNum] - 203) % 9 == 0) {
			IOWR_VGA(VGA_BASE, 15, nextY * 28 + ghostX[ghostNum]);
			nextContent = IORD_VGA(VGA_BASE, 0);
			if(nextContent == 26 || nextContent == 27 || nextContent == 28
					|| nextContent == 17 || nextContent == 18)
				return 1;
		}
		break;
	default:
		break;
	}
	return 0;
}
//---------------------------------------------------------------------------------------------
int randomMode(int ghostNum) {
	int optionNum = 0;
	//compute all the possible directions at time
	int i;
	for(i = 0; i < 4; i++) {
		ghostOption[ghostNum][i] = isAvailable(ghostNum, i + 1);
		optionNum += ghostOption[ghostNum][i];
	}

	int choice = 0;
	switch(optionNum) {
		case 0:	//no available direction
			return 0;
		case 1:	//choose the only available direction
			for(i = 0; i < 4; i++) {
				if(ghostOption[ghostNum][i] == 1)
					return i + 1;
			}
			break;
			//choose direction according to current moving direction & random choice
		case 2:
		switch(ghostMove[ghostNum]) {
			case 1:
				if(ghostOption[ghostNum][0] == 1)
					return 1;
				else if(ghostOption[ghostNum][1] == 1)
					return 2;
				else
					return 4;
			case 2:
				if(ghostOption[ghostNum][0] == 1)
					return 1;
				else if(ghostOption[ghostNum][1] == 1)
					return 2;
				else
					return 3;
			case 3:
				if(ghostOption[ghostNum][1] == 1)
					return 2;
				else if(ghostOption[ghostNum][2] == 1)
					return 3;
				else
					return 4;
			case 4:
				if(ghostOption[ghostNum][0] == 1)
					return 1;
				else if(ghostOption[ghostNum][2] == 1)
					return 3;
				else
					return 4;
			default:
				break;
			}
		break;
		case 3:
			choice = rand() % 2;
			int badDirection = 0;
			for(i = 0; i < 4; i++) {
				if(ghostOption[ghostNum][i] == 0)
					badDirection = i + 1;
			}
			switch(ghostMove[ghostNum]) {
			case 1:
				if(badDirection == 1) {
					if(choice == 0)
						return 2;
					else
						return 4;
				}
				else if(badDirection == 2) {
					if(choice == 0)
						return 1;
					else
						return 4;
				}
				else {
					if(choice == 0)
						return 1;
					else
						return 2;
				}
			case 2:
				if(badDirection == 1) {
					if(choice == 0)
						return 2;
					else
						return 3;
				}
				else if(badDirection == 2) {
					if(choice == 0)
						return 1;
					else
						return 3;
				}
				else {
					if(choice == 0)
						return 1;
					else
						return 2;
				}
			case 3:
				if(badDirection == 2) {
					if(choice == 0)
						return 3;
					else
						return 4;
				}
				else if(badDirection == 3) {
					if(choice == 0)
						return 2;
					else
						return 4;
				}
				else {
					if(choice == 0)
						return 2;
					else
						return 3;
				}
			case 4:
				if(badDirection == 1) {
					if(choice == 0)
						return 3;
					else
						return 4;
				}
				else if(badDirection == 3) {
					if(choice == 0)
						return 1;
					else
						return 4;
				}
				else {
					if(choice == 0)
						return 1;
					else
						return 3;
				}
			default: break;
			}
			break;
		case 4:
			choice = rand() % 3;
			switch(ghostMove[ghostNum]) {
			case 1:
				if(choice == 0)
					return 1;
				else if(choice == 1)
					return 2;
				else
					return 4;
			case 2:
				if(choice == 0)
					return 1;
				else if(choice == 1)
					return 2;
				else
					return 3;
			case 3:
				if(choice == 0)
					return 2;
				else if(choice == 1)
					return 3;
				else
					return 4;
			case 4:
				if(choice == 0)
					return 1;
				else if(choice == 1)
					return 3;
				else
					return 4;
			default: break;
			}
			break;
			default: break;
	}
	return 0;
}
//---------------------------------------------------------------------------------------------
int chaseMode(int ghostNum, int x, int y) {
	int i;
	for(i = 0; i < 4; i++) {
		ghostOption[ghostNum][i] = isAvailable(ghostNum, i + 1);
	}
	//make choice depending on target position
	if(ghostImgX[ghostNum] > x) {
		if(ghostImgY[ghostNum] > y) {	//ghost is at right-bottom of the target
			if(ghostOption[ghostNum][2] == 1 && ghostOption[ghostNum][3] == 1) {
				if(ghostMove[ghostNum] == 1)
					return 4;
				else if(ghostMove[ghostNum] == 2)
					return 3;
				else {
					int choice = rand() % 2;
					if(choice == 0 && ghostMove[ghostNum] != 1)
						return 3;
					else if(choice == 1 && ghostMove[ghostNum] != 2)
						return 4;
				}
			}
			if(ghostOption[ghostNum][2] == 1 && ghostOption[ghostNum][3] == 0
					&& ghostMove[ghostNum] != 1)
				return 3;
			if(ghostOption[ghostNum][2] == 0 && ghostOption[ghostNum][3] == 1
					&& ghostMove[ghostNum] != 2)
				return 4;
		}
		else if(ghostImgY[ghostNum] < y) {	//ghost is at right-top of the target
			if(ghostOption[ghostNum][1] == 1 && ghostOption[ghostNum][2] == 1) {
				if(ghostMove[ghostNum] == 1)
					return 2;
				else if(ghostMove[ghostNum] == 4)
					return 3;
				else {
					int choice = rand() % 2;
					if(choice == 0 && ghostMove[ghostNum] != 4)
						return 2;
					else if(choice == 1 && ghostMove[ghostNum] != 1)
						return 3;
				}
			}
			if(ghostOption[ghostNum][1] == 1 && ghostOption[ghostNum][2] == 0
					&& ghostMove[ghostNum] != 4)
				return 2;
			if(ghostOption[ghostNum][1] == 0 && ghostOption[ghostNum][2] == 1
					&& ghostMove[ghostNum] != 1)
				return 3;
		}
		else {	//ghost is at right of the target
			if(ghostOption[ghostNum][2] == 1 && ghostMove[ghostNum] != 1)
				return 3;
		}
	}
	else if(ghostImgX[ghostNum] < x) {
		if(ghostImgY[ghostNum] > y) {	//ghost is at left-bottom of the target
			if(ghostOption[ghostNum][0] == 1 && ghostOption[ghostNum][3] == 1) {
				if(ghostMove[ghostNum] == 3)
					return 4;
				else if(ghostMove[ghostNum] == 2)
					return 1;
				else {
					int choice = rand() % 2;
					if(choice == 0 && ghostMove[ghostNum] != 3)
						return 1;
					else if(choice ==1 && ghostMove[ghostNum] != 2)
						return 4;
				}
			}
			if(ghostOption[ghostNum][0] == 1 && ghostOption[ghostNum][3] == 0
					&& ghostMove[ghostNum] != 3)
				return 1;
			if(ghostOption[ghostNum][0] == 0 && ghostOption[ghostNum][3] == 1
					&& ghostMove[ghostNum] != 2)
				return 4;
		}
		else if(ghostImgY[ghostNum] < y) {	//ghost is at left-top of the target
			if(ghostOption[ghostNum][0] == 1 && ghostOption[ghostNum][1] == 1) {
				if(ghostMove[ghostNum] == 4)
					return 1;
				else if(ghostMove[ghostNum] == 3)
					return 2;
				else {
					int choice = rand() % 2;
					if(choice == 0 && ghostMove[ghostNum] != 3)
						return 1;
					else if(choice == 1 && ghostMove[ghostNum] != 4)
						return 2;
				}
			}
			if(ghostOption[ghostNum][0] == 1 && ghostOption[ghostNum][1] == 0
					&& ghostMove[ghostNum] != 3)
				return 1;
			if(ghostOption[ghostNum][0] == 0 && ghostOption[ghostNum][1] == 1
					&& ghostMove[ghostNum] != 4)
				return 2;
		}
		else {	//ghost is at left of the target
			if(ghostOption[ghostNum][0] == 1 && ghostMove[ghostNum] != 3)
				return 1;
		}
	}
	else
	{
		if(ghostImgY[ghostNum] > y) {	//ghost is at bottom of the target
			if(ghostOption[ghostNum][3] == 1 && ghostMove[ghostNum] != 2)
				return 4;
		}
		else if(ghostImgY[ghostNum] < y) {	//ghost is at top of the target
			if(ghostOption[ghostNum][1] == 1 && ghostMove[ghostNum] != 4)
				return 2;
		}
		else {	//ghost reaches target
			return 0;
		}
	}

	if(ghostOption[ghostNum][ghostMove[ghostNum] - 1] == 1)
		return ghostMove[ghostNum];

	return randomMode(ghostNum);
}
//---------------------------------------------------------------------------------------------
void moveGhost(int ghostNum) {
	if(pacDie == 0) {
		if(ghostEaten[ghostNum] == 0) {
		//random or chasing?
			if(ghostWeakMode[ghostNum] == 0) {
				if(ghostMode[ghostNum] < ghostModeSwitchTime[ghostNum] / 2)
					ghostOperation[ghostNum] = randomMode(ghostNum);
				else
					ghostOperation[ghostNum] = chaseMode(ghostNum, pacImgX, pacImgY);
				ghostMode[ghostNum] = (ghostMode[ghostNum] + 1) % ghostModeSwitchTime[ghostNum];
			}
			else
				ghostOperation[ghostNum] = randomMode(ghostNum);
		}
		else {
			ghostOperation[ghostNum] = chaseMode(ghostNum, 203 + INITIAL_GHOST_X * 9, 105 + INITIAL_GHOST_Y * 9);
		}

		switch(ghostOperation[ghostNum]) {
		case 1:	//right
			if(ghostImgX[ghostNum] < 446) {
				if(ghostWeakMode[ghostNum] % 2 == 0) {
					ghostImgX[ghostNum] += ghostV[ghostNum];
					ghostMove[ghostNum] = 1;
				}
			}
			else {
				ghostImgX[ghostNum] = 203;
				ghostMove[ghostNum] = 1;
			}
			break;
		case 2:	//down
			if(ghostWeakMode[ghostNum] % 2 == 0) {
				ghostImgY[ghostNum] += ghostV[ghostNum];
				ghostMove[ghostNum] = 2;
			}
			break;
		case 3: //left
			if(ghostImgX[ghostNum] >= 203) {
				if(ghostWeakMode[ghostNum] % 2 == 0) {
					ghostImgX[ghostNum] -= ghostV[ghostNum];
					ghostMove[ghostNum] = 3;
				}
			}
			else {
				ghostImgX[ghostNum] = 446;
				ghostMove[ghostNum] = 3;
			}
			break;
		case 4: //up
			if(ghostWeakMode[ghostNum] % 2 == 0) {
				ghostImgY[ghostNum] -= ghostV[ghostNum];
				ghostMove[ghostNum] = 4;
			}
			break;
		default:
			break;
		}

		ghostX[ghostNum] = (ghostImgX[ghostNum] - 203) / 9;
		ghostY[ghostNum] = (ghostImgY[ghostNum] - 105) / 9;
		if(ghostX[ghostNum] == pacX && ghostY[ghostNum] == pacY) {
			if(ghostWeakMode[ghostNum] == 0 && ghostEaten[ghostNum] == 0) {
				pacDie = 1;
				pacLife--;
			}
			else {
				ghostEaten[ghostNum] = 1;
				ghostWeakMode[ghostNum] = 0;
			}
		}
		if(ghostEaten[ghostNum] == 1) {
			if(ghostX[ghostNum] == INITIAL_GHOST_X && ghostY[ghostNum] == INITIAL_GHOST_Y)
				ghostEaten[ghostNum] = 0;
		}
	}

	paintGhost(ghostNum);
}
//---------------------------------------------------------------------------------------------
void startPac() {
	srand(time(NULL));
	printf("[New Game]\n");
	score = 0;
	pacLife = INITIAL_PAC_LIFE;
	level = 1;
	gameSpeed = INITIAL_GAME_SPEED;
	initializeStage();
	while(pacLife > 0) {
		while(!IORD_8DIRECT(KEYBOARD_BASE,0)){
			int i;
			for(i = 0; i < gameSpeed; i++);
			movePac();
			for(i = 0; i < 3; i++)
				moveGhost(i);
			if(pacDot == 0) {
				int i;
				for(i = 0; i < 10 * gameSpeed; i++);
				initializeStage();
			}
		}
		keyBoardCode = IORD_8DIRECT(KEYBOARD_BASE,1);
		movePac();
		int i;
		for(i = 0; i < 3; i++)
			moveGhost(i);
		if(pacDot == 0) {
			int i;
			for(i = 0; i < 10 * gameSpeed; i++);
			initializeStage();
		}
	}
}
//---------------------------------------------------------------------------------------------
int modeChoose() {
	int gameMode = 0;	//1P or 2P
	IOWR_VGA(VGA_BASE, 14, 1);
	IOWR_VGA(VGA_BASE, 12, 0);
	IOWR_VGA(VGA_BASE, 18, 51);
	IOWR_VGA(VGA_BASE, 12, 6);
	IOWR_VGA(VGA_BASE, 18, 28);
	unsigned modeSelection;
	for(;;) {
		while(!IORD_8DIRECT(KEYBOARD_BASE,0));
		modeSelection = IORD_8DIRECT(KEYBOARD_BASE,1);
		switch(modeSelection) {
		case 117:
			gameMode = 0;	//1P
			IOWR_VGA(VGA_BASE, 12, 0);
			IOWR_VGA(VGA_BASE, 18, 51);
			IOWR_VGA(VGA_BASE, 12, 6);
			IOWR_VGA(VGA_BASE, 18, 28);
			break;
		case 114:
			gameMode = 1;	//2P
			IOWR_VGA(VGA_BASE, 12, 0);
			IOWR_VGA(VGA_BASE, 18, 28);
			IOWR_VGA(VGA_BASE, 12, 6);
			IOWR_VGA(VGA_BASE, 18, 51);
			break;
		case 90:
			return gameMode;
			break;
		default:
			break;
		}
	}
	return 0;
}
//---------------------------------------------------------------------------------------------
int main() {
	//printf("Hello from Nios II!\n");
    long unsigned length = sizeof(begin);
    //printf("%lu",length);
    int i = 0;
    unsigned indicator;
    indicator = IORD_8DIRECT(AUDIO_PLAYER_BUFFER_BASE,0);
    for (;;){
	  indicator = IORD_8DIRECT(AUDIO_PLAYER_BUFFER_BASE,0);
	  if (indicator == 0x00000000){
		  IOWR_8DIRECT(AUDIO_PLAYER_BUFFER_BASE,0,begin[i]);
		  i++;
	  }
	  if (i == length - 1){
		  break;
	  }
    }
    length = sizeof(intermission);
    i = 0;
    for (;;){
	  indicator = IORD_8DIRECT(AUDIO_PLAYER_BUFFER_BASE,0);
	  if (indicator == 0x00000000){
		  IOWR_8DIRECT(AUDIO_PLAYER_BUFFER_BASE,0,intermission[i]);
		  i++;
	    }
		if (i == length - 1){
		  break;
		}
	}

	printf("[Staring PacMan] ...\n");
	for(;;)
	{
		if(modeChoose() == 0)
			startPac();
		else
			;
	}
	return 0;
}


