#include <io.h>
#include <system.h>
#include <stdio.h>
#include <time.h>

/*
 * sram distribution
 * (31) 0,1 for differnt face (2,13) for player
 * (3,12) (4,11) (5,10) for enemies
 * (30) 0,1,2 for different face (0,15) for boss
 * (1,14) for bullet
 * (7,8) for firework
 *
 */
#define IOWR_SRAM_DATA(base, offset, data) \
  IOWR_16DIRECT(base, (offset) * 2, data)
#define IORD_SRAM_DATA(base, offset) \
  IORD_16DIRECT(base, (offset) * 2)

int main()
{
	//define all the variable

    int flag = 0;   // use to determine what state we are

    int gameTime = 0;   // time count
    int score = 0;  // score count

    int deadFlag;  //indicates player has been created
    int playerXCoordinate;   //player's leftmost upmost coordinate
    int playerYCoordinate;
    int life;   //indicate how many life still left
    int openMouthTime;	//time period for open mouth animation

    int bossFlag;    //indicates boss has been created
    int bossXCoordinate; //boss's leftmost upmost coordinate
    int bossYCoordinate;
    int bossLife;	//indicate how many life boss still left

    int enemyCount; // number of enemies in the screen up to 8 enemies
    int enemyFlag[9];	//indicate whethor enemy exists max to 10
    int enemyXCoordinate[9];  //enemies' leftmost upmost coordinate
    int enemyYCoordinate[9];
    int fireworkTime;	//time period for firework animation

    int bulletFlag; //indicate bullet created
    int bulletXCoordinate;	//bullet leftmost upmost coordinate
    int bulletYCoordinate;

    int playerXSpeed;	//speed for everything
    int playerYSpeed;
    int enemyXSpeed;
    int enemyYSpeed;
    int bossXSpeed;
    int bossYSpeed;
    int bulletXSpeed;

    int xLowBound = 0;		// bound for the screen pixels
    int xHighBound = 640;
    int yLowBound = 0;
    int yHighBound = 480;

    int counterTime;	// raise the clock to make a loop longer
    int counterFly;
    int	counterDrop;
    int counterNormal;
    int shine =0;	// variable for dead effect


    playerXCoordinate = 40;		// init positions
	playerYCoordinate = 360;
	bossXCoordinate = 550;
	bossYCoordinate = 400;
	bulletXCoordinate = 600;
	bulletYCoordinate = 480;

	playerYSpeed = 1;	//init speeds
	enemyXSpeed = 1;
	bossXSpeed = 0;
	bossYSpeed = 0;
	bulletXSpeed = 4;

	deadFlag = 0;	//int flags
	bossFlag = 0;
	bulletFlag = 0;
	life = 3;	//init lifes

	int i = 0;	//init for enemyflags
	int j = 0;
	for(i = 0; i < 10; i++){
		enemyFlag[i] = 0;
		enemyXCoordinate[i] = 800;
		enemyYCoordinate[i] = 800;
	}
	enemyCount = 0;

	counterTime = 10000;	//init counters
	counterDrop = 10000;
	counterFly = 10000;
	counterNormal = 10000;

	srand(time(NULL));	//init rand seed

	IOWR_SRAM_DATA(VGA_BASE,31, 0);	// init player and boss initial faces
	IOWR_SRAM_DATA(VGA_BASE,30, 0);

	openMouthTime = 0;	//init animation time
	fireworkTime = 0;



	for (; ; ) {

		// get sound from avalon bus
		int sound = IORD_16DIRECT(AUDIOSLAVE_BASE,0);

		counterTime--;
		//simulate real time
		if(counterTime == 0){
			counterTime = 1000000;	//215000 times the clock time
			gameTime = gameTime + 1;
			score = score + 10;
			//if(gameTime%10 == 0){
				printf("%d seconds since game starts \n", gameTime);
			//}
		}

		//main function
		if( sound < 1500 || sound >64035 || (sound>32000 && sound< 33000)){
			// no sound input case
			counterDrop--;
			//counterFly = 10000;	//problem
			if(counterDrop == 0){
				counterDrop = 10000;
				if(flag > 0 && flag <= 10){
					// shot case
					flag = 0;	//problem
					printf("shot at %d ------------------- \n", playerYCoordinate);

					// create bullet
					if(bulletFlag == 0 ){
						bulletXCoordinate = 70;
						bulletYCoordinate = playerYCoordinate + 50;
						bulletFlag = 1;
						//open mouth
						while(IORD_SRAM_DATA(VGA_BASE, 31)!=1){
							IOWR_SRAM_DATA(VGA_BASE,31, 1);
						}
						openMouthTime = gameTime;
					}
				}else{
					// drop case
					flag = 0;	//problem
					//printf("drop >>>>>>>>>>>>>>>>>>>>\n");

					//player moving ----  drop
					playerYSpeed = 1;
					if(yHighBound - playerYCoordinate >= 90){
						playerYCoordinate = playerYCoordinate + playerYSpeed;
					}
				}
			}

		}else{
			//got sound input case = fly case
			counterFly--;
			counterDrop = 10000;	//problem
			if(counterFly == 0){
				//printf("fly <<<<<<<<<<<<<<<<<<<<<<<< \n");
				counterFly = 10000;
				flag = flag + 1;

				printf("%d!!!!!!!!!!!!!!!!!!\n", flag);
				//player moving ----  fly
				playerYSpeed = -5;
				if( (sound > 10000 && sound <30000) || (sound <55535 && sound>35535 )){
					playerYSpeed = -10;
				}
				if(playerYCoordinate - yLowBound >= 100){
					playerYCoordinate = playerYCoordinate + playerYSpeed;
				}
			}
		}


		counterNormal--;
		if(counterNormal == 0){
			//usual event
			counterNormal = 10000;

			//shine and super mode after dead
			if(deadFlag == 1){
				if(shine == 10 || shine == 20 || shine == 30 || shine == 40 || shine == 50 || shine == 60 || shine == 70 || shine == 80 || shine == 90 ){
					IOWR_SRAM_DATA(VGA_BASE, 2, 800);
					IOWR_SRAM_DATA(VGA_BASE, 13, 800);
					shine = shine + 1;
				}else if(shine == 100){
					IOWR_SRAM_DATA(VGA_BASE, 2, 800);
					IOWR_SRAM_DATA(VGA_BASE, 13, 800);
					deadFlag = 0;
					shine = 0;
					printf("super mode over \n");
				}else{

					IOWR_SRAM_DATA(VGA_BASE, 2, playerXCoordinate);
					IOWR_SRAM_DATA(VGA_BASE, 13, playerYCoordinate);
					shine = shine + 1;
				}
			}else{

				while(IORD_SRAM_DATA(VGA_BASE, 13)!= playerYCoordinate){
					IOWR_SRAM_DATA(VGA_BASE, 2, playerXCoordinate);
					IOWR_SRAM_DATA(VGA_BASE, 13, playerYCoordinate);
				}
			}


			//enemy created
			int randNumberSeed = rand()%1000;
			int randNumber = randNumberSeed%100;
			if(randNumber  > 97 && enemyCount < 3){
				//rand is from 0-99, thus 0.01% runs created enemy
				//create enemy of No.(enemyCount + 1)
				i = 0;
				//find the emtpy flag
				while(enemyFlag[i] == 1 && i<5){
					i++;
				}
				//assign random position
				enemyXCoordinate[i] = 620;
				enemyYCoordinate[i] = (randNumberSeed/3) + 10;

				//
				if( enemyYCoordinate[i] >= 100){
					enemyFlag[i] = 1;
					//make sure enemy don't overlap for hardware
					for(j=0; j< i; j++){
						if(abs(enemyYCoordinate[i] - enemyYCoordinate[j]) <= 80 && abs(enemyXCoordinate[i] - enemyXCoordinate[j] <= 60)){
							enemyFlag[i] = 0;
						}
					}
					if(i < 3){
						for(j=i+1; j< 3; j++){
							if(abs(enemyYCoordinate[i] - enemyYCoordinate[j]) <= 80 && abs(enemyXCoordinate[i] - enemyXCoordinate[j] <= 60)){
								enemyFlag[i] = 0;
							}
						}
					}
					if(enemyFlag[i] == 1){
						enemyCount++;
						printf("an enemy emerge at %d, there are %d enemies \n",enemyYCoordinate[i], enemyCount + 1);
					}
				}
			}


			//enemy engaging
			for(i = 0; i < 3; i++){
				if(enemyFlag[i] == 1){
					enemyXCoordinate[i] = enemyXCoordinate[i] - enemyXSpeed;
					if(enemyXCoordinate[i] < 20){
						enemyFlag[i] = 0;
						enemyCount --;
						while(IORD_SRAM_DATA(VGA_BASE, 3+i) != 800){
							IOWR_SRAM_DATA(VGA_BASE, 3+i , 800);
							IOWR_SRAM_DATA(VGA_BASE,12-i, 800);
						}
						printf("an enemy passed, there are %d enemies \n", enemyCount + 1);
					}else{
					IOWR_SRAM_DATA(VGA_BASE,3+i, enemyXCoordinate[i]);
					IOWR_SRAM_DATA(VGA_BASE,12-i, enemyYCoordinate[i]);
					}
				}
			}



			//boss created
			if(gameTime > 1 && gameTime < 3 && bossFlag == 0){
				//create boss only between a time
				bossFlag = 1;
				printf("boss created \n");
				bossLife = 1000;
				//assign init position
				bossXCoordinate = 550;
				bossYCoordinate = 400;
				// first face
				IOWR_SRAM_DATA(VGA_BASE,30, 0);
				IOWR_SRAM_DATA(VGA_BASE, 0, 550);
				IOWR_SRAM_DATA(VGA_BASE, 15, 400);
			}
			if(gameTime > 25 && gameTime < 35){
				// second face
				IOWR_SRAM_DATA(VGA_BASE,30, 1);
			}

			if(gameTime > 35 && gameTime < 37){
				//third face and move
				IOWR_SRAM_DATA(VGA_BASE,30, 2);
				bossYSpeed = -2;
				bossXSpeed = 1;
				bossLife = 3;
			}
			//boss engaging
			if(bossFlag == 1){
				if(bossYCoordinate - yLowBound <= 100){
					bossYSpeed = -bossYSpeed;
				}
				if(yHighBound - bossYCoordinate <= 79){
					bossYSpeed = -bossYSpeed;
				}
				bossXCoordinate = bossXCoordinate - bossXSpeed;
				bossYCoordinate = bossYCoordinate + bossYSpeed;
				if(bossXCoordinate < 20){
					bossFlag = 0;
					printf("boss passed \n");
					IOWR_SRAM_DATA(VGA_BASE, 0, 800);
					IOWR_SRAM_DATA(VGA_BASE, 15, 800);
					bossXCoordinate = 550;
					bossYCoordinate = 400;
				}else{
					//give it to hardware
					IOWR_SRAM_DATA(VGA_BASE, 0, bossXCoordinate);
					IOWR_SRAM_DATA(VGA_BASE, 15, bossYCoordinate);
				}
			}


			// close mouth
			if(gameTime - openMouthTime > 0){
				//openMouthTime = 10000;
				IOWR_SRAM_DATA(VGA_BASE, 31, 0);
			}


			//bullet engaging
			if(bulletFlag == 1){
				bulletXCoordinate = bulletXCoordinate + bulletXSpeed;
				if(bulletXCoordinate > xHighBound + 10){
					bulletFlag = 0;
				}
				IOWR_SRAM_DATA(VGA_BASE, 1, bulletXCoordinate);
				IOWR_SRAM_DATA(VGA_BASE, 14, bulletYCoordinate);
			}


			//hit boss happens
			if(bulletFlag == 1 && bossFlag == 1 && abs(bulletXCoordinate-bossXCoordinate) <= 40 && bulletYCoordinate - bossYCoordinate <= 80 && bulletYCoordinate - bossYCoordinate >= -25) {
					//assign hit position
					printf("hit boss happen \n");
					bossLife = bossLife - 1;
					if(bossLife == 0){
						// boss died
						bossFlag = 0;
						IOWR_SRAM_DATA(VGA_BASE,30, 0);
						// provide firework
						IOWR_SRAM_DATA(VGA_BASE, 7 , bossXCoordinate);
						IOWR_SRAM_DATA(VGA_BASE, 8 , bossYCoordinate);
						fireworkTime = gameTime;
					}
					bulletFlag = 0;
					IOWR_SRAM_DATA(VGA_BASE, 1, 800);
					IOWR_SRAM_DATA(VGA_BASE, 14, 800);
					IOWR_SRAM_DATA(VGA_BASE, 0, 800);
					IOWR_SRAM_DATA(VGA_BASE, 15, 800);
					score = score + 1000;
			}
			//hit enemy happens
			for(i=0; i<3; i++){
				if(bulletFlag == 1 && enemyFlag[i] == 1 && abs(bulletXCoordinate-enemyXCoordinate[i]) <= 40 && bulletYCoordinate - enemyYCoordinate[i] <= 80 && bulletYCoordinate - enemyYCoordinate[i] >= -25) {
						//assign hit position
						printf("hit enemy happen , there are now %d enemies \n", enemyCount);
						enemyFlag[i] = 0;
						bulletFlag = 0;
						enemyCount--;
						IOWR_SRAM_DATA(VGA_BASE, 1, 800);
						IOWR_SRAM_DATA(VGA_BASE, 14, 800);
						while(IORD_SRAM_DATA(VGA_BASE, 3+i) != 800){
							IOWR_SRAM_DATA(VGA_BASE, 3+i , 800);
							IOWR_SRAM_DATA(VGA_BASE,12-i, 800);
						}
						score = score + 100;
						// provide firework

						while(IORD_SRAM_DATA(VGA_BASE, 7) != enemyXCoordinate[i] || IORD_SRAM_DATA(VGA_BASE, 8) != enemyYCoordinate[i]){
						IOWR_SRAM_DATA(VGA_BASE, 7 , enemyXCoordinate[i]);
						IOWR_SRAM_DATA(VGA_BASE, 8 , enemyYCoordinate[i]);
						}
						fireworkTime = gameTime;
					}
				}


			// shutdown firework
			if(gameTime - fireworkTime > 0){
				while(IORD_SRAM_DATA(VGA_BASE, 7) != 800){
				IOWR_SRAM_DATA(VGA_BASE, 7 , 800);
				IOWR_SRAM_DATA(VGA_BASE, 8 , 800);
				}
			}


			//collision boss happens
			if(deadFlag == 0 && bossFlag == 1 && bossXCoordinate - playerXCoordinate>0 && bossXCoordinate - playerXCoordinate <= 40 && abs(bossYCoordinate - playerYCoordinate) <= 60){
				//assign collision happens
				deadFlag = 1;
				life = life - 1;
				printf("player is dead contacting boss, has life %d \n", life);
			}
			//collision enemy happens
			for(i=0; i < 3; i++){
				if(deadFlag == 0 && enemyFlag[i] == 1 && enemyXCoordinate[i] - playerXCoordinate>0 && enemyXCoordinate[i] - playerXCoordinate <= 40 && abs(enemyYCoordinate[i] - playerYCoordinate) <= 60){
					//assign collision happens
					deadFlag = 1;
					enemyFlag[i] = 0;
					enemyCount--;
					life = life - 1;
					printf("player is dead contacting enemy, has life %d \n", life);

					while(IORD_SRAM_DATA(VGA_BASE, 3+i) != 800){
						IOWR_SRAM_DATA(VGA_BASE, 3 + i, 800);
						IOWR_SRAM_DATA(VGA_BASE, 12 - i, 800);
					}
				}
			}


			//game over happen
			if(life == 0){
				//create game over
				printf("no life. Game over \n");
				printf("score is %d \n ", score);
			}



			//finish game
			if(gameTime > 8000){
				// player survive
				gameTime = 0;
				openMouthTime = 0;
				bossYSpeed = 0;
				bossXSpeed = 0;
				bossLife = 1000;
				if(life > 0){
					score = score + life * 1000;
				}
				life = 3;
				printf("time out . Game over \n");
				printf("score is %d", score);
			}
		}
	}
}
