//
// An example Lynx game. I'm not entirely happy with the collision detection
// but it's decent enough.
// Use the Fire button to use up your power gauge and spawn helper balls!
//
//  If you have any questions regarding the code, contact me
//  via the method specified at  http://www.sebastianmihai.com
//  (operational in 2012), and I will try my best to help.
//
//                             Sebastian Mihai, 2012
//

#include <lynx.h>
#include <6502.h>
#include <conio.h>
#include <joystick.h>
#include <tgi.h>
#include "../resident/resident.h"
#include "../resident/abcmusic.h"
#define tgi_flip() tgi_ioctl(1, 0)
//#define tgi_setbgcolor(val) tgi_ioctl(2, (unsigned)(val))

static char drawPending;

#define PADDLE_LENGTH 24
#define PADDLE_WIDTH 2
#define PADDLE_Y 88
#define PADDLE_SPEED 3

#define MAX_BALLS 10
#define DELAY 500
  #define d_NE 0
  #define d_NW 1
  #define d_SW 2
  #define d_SE 3

static void
usleep(int n)
{
    int i;
    for (i = 0; i < n; i++)
	abc_update();
}

char b = 1;
extern unsigned char drawpage;
int topBound, bottomBound, leftBound, rightBound;

void draw_ball( int x, int y, unsigned char colour ) {
	tgi_setcolor(colour);
    tgi_setpixel(x, y);
	tgi_setpixel(x+1, y);
	tgi_setpixel(x+1, y+1);
	tgi_setpixel(x, y+1);
}

void bounce_ball( int* x, int* y, unsigned char* direction );

void move_ball( int* x, int* y, unsigned char* direction ) {
	int newX, newY;
	unsigned char newDirection;
	
	newX = *x;
	newY = *y;
	newDirection = *direction;
	
	if( newDirection == d_NE ) { newX++, newY--; }
	if( newDirection == d_NW ) { newX--, newY--; }
	if( newDirection == d_SW ) { newX--, newY++; }
	if( newDirection == d_SE ) { newX++, newY++; }
	
	*x = newX;
	*y = newY;
	
	bounce_ball( x, y, direction );
}



// bounce v3
void bounce_ball( int* x, int* y, unsigned char* direction ) {
	int newX, newY;
	unsigned char newDirection;
	
	newX = *x;
	newY = *y;
	newDirection = *direction;
	
			if( newDirection == d_NE ) {
				if( newX >= rightBound-1 && newY <= topBound ) {
					newDirection = d_SW;
				} else if ( newX >= rightBound-1 ) {
					newDirection = d_NW;
				} else if ( newY <= topBound ) {
					newDirection = d_SE;
				}
			}

			if( newDirection == d_NW ) {
				if( newX <= leftBound && newY <= topBound ) {
					newDirection = d_SE;
				} else if ( newX <= leftBound ) {
					newDirection = d_NE;
				} else if ( newY <= topBound ) {
					newDirection = d_SW;
				}
			}

			if( newDirection == d_SW ) {
				if( newX <= leftBound && newY >= bottomBound-1 ) {
					newDirection = d_NE;
				} else if ( newX <= leftBound ) {
					newDirection = d_SE;
				} else if ( newY >= bottomBound-1 ) {
					newDirection = d_NW;
				}
			}

			if( newDirection == d_SE ) {
				if( newX >= rightBound-1 && newY >= bottomBound-1 ) {
					newDirection = d_NW;
				} else if ( newX >= rightBound-1 ) {
					newDirection = d_SW;
				} else if ( newY >= bottomBound-1 ) {
					newDirection = d_NE;
				}
			}

	// if we find a block at the new location, we remove it, and we try to bounce again
	
	// we are moving towards NW and hit something
	if( newDirection == d_NW && tgi_getpixel(newX, newY) != COLOR_BLACK ) {
		tgi_setcolor(COLOR_BLACK);
		tgi_setpixel(newX, newY);
		if( tgi_getpixel(newX+1, newY) != COLOR_BLACK
		 && tgi_getpixel(newX, newY+1) != COLOR_BLACK ) {
			newDirection = d_SE;
		} else {
			newDirection = d_SW;
		}
		tgi_setpixel(newX-1, newY-1);
		tgi_setpixel(newX, newY-1);tgi_setpixel(newX+1, newY-1);
		tgi_setpixel(newX-1, newY);tgi_setpixel(newX-1, newY+1);
		bounce_ball( &newX, &newY, &newDirection);
	}
	else if( newDirection == d_NE && tgi_getpixel(newX+1, newY) != COLOR_BLACK ) {
		tgi_setcolor(COLOR_BLACK);
		tgi_setpixel(newX+1, newY);
		if( tgi_getpixel(newX, newY) != COLOR_BLACK
		 && tgi_getpixel(newX+1, newY+1) != COLOR_BLACK ) {
			newDirection = d_SW;
		} else {
			newDirection = d_SE;
		}
		tgi_setpixel(newX+2, newY);tgi_setpixel(newX+2, newY+1);
		tgi_setpixel(newX+1, newY-1);tgi_setpixel(newX, newY-1);
		tgi_setpixel(newX+2, newY-1);
		bounce_ball( &newX, &newY, &newDirection);
	}
	else if( newDirection == d_SE && tgi_getpixel(newX+1, newY+1) != COLOR_BLACK ) {
		tgi_setcolor(COLOR_BLACK);
		tgi_setpixel(newX+1, newY+1);
		if( tgi_getpixel(newX+1, newY) != COLOR_BLACK
		 && tgi_getpixel(newX, newY+1) != COLOR_BLACK ) {
			newDirection = d_NW;
		} else {
			newDirection = d_NE;
		}
		tgi_setpixel(newX+2, newY+1);tgi_setpixel(newX+2, newY);
		tgi_setpixel(newX+1, newY+2);tgi_setpixel(newX, newY+2);
		tgi_setpixel(newX+2, newY+2);
		bounce_ball( &newX, &newY, &newDirection);
	}
	else if( newDirection == d_SW && tgi_getpixel(newX, newY+1) != COLOR_BLACK ) {
		tgi_setcolor(COLOR_BLACK);
		tgi_setpixel(newX, newY+1);
		if( tgi_getpixel(newX, newY) != COLOR_BLACK
		 && tgi_getpixel(newX+1, newY+1) != COLOR_BLACK ) {
			newDirection = d_NE;
		} else {
			newDirection = d_NW;
		}
		tgi_setpixel(newX-1, newY+1);tgi_setpixel(newX-1, newY);
		tgi_setpixel(newX, newY+2);tgi_setpixel(newX+1, newY+2);
		tgi_setpixel(newX-1, newY+2);
		bounce_ball( &newX, &newY, &newDirection);
	}
			
	*x = newX;
	*y = newY;
	*direction = newDirection;
}

void drawLevel( void ) {
  tgi_setcolor(COLOR_VIOLET);
  tgi_bar(leftBound+5, topBound+5, leftBound+15, topBound+15);
  tgi_setcolor(COLOR_LIGHTCYAN);
  tgi_bar(leftBound+25, topBound+5, leftBound+35, topBound+15);
  tgi_setcolor(COLOR_YELLOW);
  tgi_bar(leftBound+45, topBound+5, leftBound+55, topBound+15);
  tgi_setcolor(COLOR_RED);
  tgi_bar(leftBound+65, topBound+5, leftBound+75, topBound+15);
  tgi_setcolor(COLOR_GREEN);
  tgi_bar(leftBound+85, topBound+5, leftBound+95, topBound+15);
  
  tgi_setcolor(COLOR_BLUE);
  tgi_bar(leftBound+10, topBound+20, leftBound+20, topBound+30);
  tgi_setcolor(COLOR_WHITE);
  tgi_bar(leftBound+30, topBound+20, leftBound+40, topBound+30);
  tgi_setcolor(COLOR_VIOLET);
  tgi_bar(leftBound+50, topBound+20, leftBound+60, topBound+30);
  tgi_setcolor(COLOR_GREY);
  tgi_bar(leftBound+70, topBound+20, leftBound+80, topBound+30);
  tgi_setcolor(COLOR_CYAN);
  tgi_bar(leftBound+90, topBound+20, leftBound+100, topBound+30);
  
  tgi_setcolor(COLOR_GREEN);
  tgi_bar(leftBound+5, topBound+35, leftBound+15, topBound+45);
  tgi_setcolor(COLOR_RED);
  tgi_bar(leftBound+25, topBound+35, leftBound+35, topBound+45);
  tgi_setcolor(COLOR_YELLOW);
  tgi_bar(leftBound+45, topBound+35, leftBound+55, topBound+45);
  tgi_setcolor(COLOR_LIGHTCYAN);
  tgi_bar(leftBound+65, topBound+35, leftBound+75, topBound+45);
  tgi_setcolor(COLOR_VIOLET);
  tgi_bar(leftBound+85, topBound+35, leftBound+95, topBound+45);
}

int maingame(void)
{
  int w, h;
  int paddleX;
  int i, j, ballsToSpawn;
  unsigned long currentFrame = 0;
  int frameWidth=30, frameHeight=10;
  unsigned char nrofcolors, background, framecolor;
  char *stitle = "CATKANOID";
  char *author = "by Sebastian Mihai";

  int power;
  
  int ballX, ballY;
  int secondBallX[MAX_BALLS], secondBallY[MAX_BALLS];
  int secondOldBallX[MAX_BALLS], secondOldBallY[MAX_BALLS];
  int secondBallFramesLeft[MAX_BALLS];
  unsigned char secondBallDirection[MAX_BALLS];
  int oldBallX, oldBallY;
  unsigned char direction = d_NW;
  
  framecolor = COLOR_BLUE;
  background = COLOR_BLACK;

  nrofcolors = tgi_getcolorcount();
  w = tgi_getxres();
  h = tgi_getyres();

  topBound=frameHeight;
  bottomBound=h - frameHeight - 1;
  leftBound=frameWidth;
  rightBound=w - frameWidth - 1;
  
  // Single display buffer
  tgi_setviewpage(drawpage);
  tgi_setdrawpage(drawpage);

  // Set our default palette to the hardware
  tgi_setpalette(tgi_getdefpalette());

  // frame and background
  tgi_setcolor(framecolor);
  tgi_bar(0, 0, w-1, h-1);
  tgi_setcolor(background);
  tgi_bar(frameWidth, frameHeight, w-frameWidth-1, h-frameHeight-1);
  
  drawLevel();
  
  tgi_setcolor(COLOR_GREEN);
  tgi_bar(leftBound-1, topBound-1, rightBound+1, topBound-1);
  tgi_bar(rightBound+1, topBound-1, rightBound+1, bottomBound+1);
  tgi_bar(leftBound-1, bottomBound+1, rightBound+1, bottomBound+1);
  tgi_bar(leftBound-1, topBound-1, leftBound-1, bottomBound+1);
  
  // Power
  tgi_setcolor(COLOR_GREEN);
  tgi_setbgcolor(COLOR_BLUE);
  tgi_outtextxy(0, 20, "P");
  tgi_outtextxy(0, 28, "O");
  tgi_outtextxy(0, 36, "W");
  tgi_outtextxy(0, 44, "E");
  tgi_outtextxy(0, 52, "R");
  power = 0;
  // paddle initial position
  paddleX = w / 2 - PADDLE_LENGTH / 2;
  
  // primary ball starting position
  ballX = 26+leftBound;
  ballY = 30+topBound;

  // second ball is invisible
  for(i=0;i<MAX_BALLS;i++) {
	  secondBallX[i] = -1;
	  secondBallY[i] = -1;
	  secondBallFramesLeft[i] = 0;
  }
  
  // display title and author
  tgi_setcolor(COLOR_YELLOW);
  tgi_setbgcolor(COLOR_BLUE);
  tgi_outtextxy(44, 0, stitle);
  tgi_setcolor(COLOR_CYAN);
  tgi_outtextxy(8,94, author);

  // Start our application
  drawPending = 0;

  // pause at beginning
  draw_ball( ballX, ballY, COLOR_WHITE );
  usleep( 9000 );
  
  while (1) {
    unsigned char joy;
    joy = joy_read(JOY_1);
	currentFrame++;
	if( currentFrame % 5 == 0 ) {
		if( power < 40 ) {
			power++;
		}
	}
	
	// frame
	tgi_setcolor(COLOR_GREEN);
	tgi_bar(leftBound-1, topBound-1, rightBound+1, topBound-1);
	tgi_bar(rightBound+1, topBound-1, rightBound+1, bottomBound+1);
	tgi_bar(leftBound-1, bottomBound+1, rightBound+1, bottomBound+1);
	tgi_bar(leftBound-1, topBound-1, leftBound-1, bottomBound+1);
	
	// Power
	//tgi_setcolor(COLOR_GREEN);
	//tgi_bar(12, 20, 17, 60);
	tgi_bar(12, 19, 17, 19);
	tgi_bar(12, 60, 17, 60);
	tgi_bar(12, 19, 12, 60);
	tgi_bar(17, 19, 17, 60);
	//and the power itself!!!
	tgi_setcolor( (power/10) + 12 );
	if( power == 40 ) {
		tgi_setcolor( currentFrame % 3 + 13 );
	}
	tgi_bar(13, 60-power, 16, 59);
	
	// save ball's position, so we can erase it
	oldBallX = ballX;
    oldBallY = ballY;
	for(i=0;i<MAX_BALLS;i++) {
		secondOldBallX[i] = secondBallX[i];
		secondOldBallY[i] = secondBallY[i];
	}
	
    if (JOY_BTN_LEFT(joy)) {
		tgi_setcolor(COLOR_BLACK);
		tgi_bar(paddleX+PADDLE_LENGTH-PADDLE_SPEED+1, PADDLE_Y, paddleX+PADDLE_LENGTH, PADDLE_Y + PADDLE_WIDTH);
		
		paddleX-=PADDLE_SPEED;
		if (paddleX < leftBound) {
			paddleX = leftBound;
		}
    }
    if (JOY_BTN_RIGHT(joy)) {  
		tgi_setcolor(COLOR_BLACK);
		tgi_bar(paddleX, PADDLE_Y, paddleX+PADDLE_SPEED-1, PADDLE_Y + PADDLE_WIDTH);
		
		paddleX+=PADDLE_SPEED;
		if (paddleX > rightBound-PADDLE_LENGTH) {	
			paddleX = rightBound-PADDLE_LENGTH;
		}
    }
	
	// spawn second ball
	if( JOY_BTN_FIRE( joy ) && power > 10 ) {
	
		if ( power == 40 ) {
			ballsToSpawn = 5;
		} else if ( power > 30 ) {
			ballsToSpawn = 3;
		} else if ( power > 20 ) {
			ballsToSpawn = 2;
		} else if ( power > 10 ) {
			ballsToSpawn = 1;
		} else {
			ballsToSpawn = 0;
		}
	
		for(j=0;j<ballsToSpawn;j++) {
			for(i=0;i<MAX_BALLS;i++) {
				if( secondBallFramesLeft[i] <= 0 ) {
					secondBallFramesLeft[i] = 100;
					secondBallX[i] = ballX;
					secondBallY[i] = ballY;
					
					secondBallDirection[i] = j % 4;
					
					break;
				}
			}
		}
		
		power = 0;
		// empty power bar
		tgi_setcolor( COLOR_BLUE );
		tgi_bar(13, 20, 16, 60);
	}
	
	// Animate secondary balls
	for(i=0;i<MAX_BALLS;i++) {
	
		if( secondBallFramesLeft[i] > 0 ) {
			secondBallFramesLeft[i]--;
			//draw second ball
			if( secondOldBallX[i] != -1 && secondOldBallY[i] != -1 ) {
				draw_ball( secondOldBallX[i], secondOldBallY[i], background );
			}
			
			if( secondBallX[i] != -1 && secondBallY[i] != -1 ) {
				move_ball( &secondBallX[i], &secondBallY[i], &secondBallDirection[i] );
				draw_ball( secondBallX[i], secondBallY[i], 9 );
			}
		} else {
			if( secondOldBallX[i] != -1 && secondOldBallY[i] != -1 ) {
				// erase it for the last time
				draw_ball( secondOldBallX[i], secondOldBallY[i], background );
				// and now make it really gone
				secondOldBallX[i] = -1;
			}
		}
	}
	
	// Animate primary ball
    draw_ball( oldBallX, oldBallY, background );
	move_ball( &ballX, &ballY, &direction );
	draw_ball( ballX, ballY, COLOR_WHITE );

	// Animate paddle
	tgi_setcolor(COLOR_YELLOW);
	tgi_bar(paddleX, PADDLE_Y, paddleX+PADDLE_LENGTH, PADDLE_Y + PADDLE_WIDTH);
	
	// tgi_getpixel(x, y);
	usleep( DELAY );
	
	// check for game over
	if( ballY > PADDLE_Y ) {
		usleep( 9000 );
		return PREV_APPLICATION;
	}
  }
  return PREV_APPLICATION;
}
