//============================================================
//============================================================
//==														==
//==				Ball Handling Routines					==
//==														==
//============================================================
//============================================================


//========================================================  Includes  

#include "Globals.h"
#include "UnivUtilities.h"
#include "Ball.h"
#include "Render.h"
#include "PlayUtils.h"
#include "SoundUtils.h"
#include "Dynamics.h"


//========================================================  Functions  
//========================================================  BallRectFromPosition  

void BallRectFromPosition (void)

{
	short		rootHeight, actualHeight;
	short		indexX, absoluteX, fractionalX;
	short		indexZ, fractionalZ;
	
	theBall.isRect.left = (theBall.xPos / 64) + displayHCenter - 5;
	theBall.isRect.right = theBall.isRect.left + 16;
	
	absoluteX = theBall.xPos;
	if (absoluteX < 0)
		absoluteX = -absoluteX;
	indexX = absoluteX / 512;
	fractionalX = absoluteX % 512;
	indexZ = (theBall.zPos / 512) + 40;
	fractionalZ = theBall.zPos % 512;
	
	rootHeight = vertTable[indexX][indexZ];
	actualHeight = rootHeight + (fractionalX * (vertTable[indexX + 1][indexZ] - rootHeight)) / 512;
	actualHeight += (fractionalZ * (vertTable[indexX][indexZ + 1] - rootHeight)) / 512;
	
	theBall.isRect.bottom = actualHeight + 4;
	theBall.isRect.top = theBall.isRect.bottom - 12;
	
	if ((theBall.isRect.bottom > screenHigh) || (theBall.isRect.top < 0) ||
			(theBall.isRect.right > screenWide) || (theBall.isRect.left < 0))
	{
		theBall.isRect = theBall.wasRect;
	}
}


//========================================================  ResetBall  

void ResetBall (void)

{
	theBall.mode = kBallFiring;
	theBall.modifier = kInitBallFiringTime + RandomInt(60) - 30;
	theBall.flag = kIsNormal;
	theBall.xPos = theBall.initXPos;
	theBall.zPos = theBall.initZPos;
	theBall.xVel = theBall.initXVel + RandomInt(3000) - 1000;
	theBall.zVel = theBall.initZVel;
	theBall.justHitWall = 0;
	theBall.dontDraw = FALSE;
	
	if (RandomCoin())			// was if (leftScoredLast) 
	{
		leftScoredLast = TRUE;
		theBall.xVel *= -1;
		theBall.xPos += 384;
	}
	else
	{
		leftScoredLast = FALSE;
		theBall.xPos -= 384;
	}
	
	thePlayer.mouseWasLetUp = TRUE;
	theOpponent.mouseWasLetUp = TRUE;
	
	BallRectFromPosition();
	
	whosGotBall = kBallIsNotHere;
	thePlayer.loopsBallHeld = 0;
	theOpponent.loopsBallHeld = 0;
	
	if (thePlayer.persona == kMissTeak)
	{
		oldDistSquared = ((long)(thePlayer.xPos) * (long)(thePlayer.xPos)) + 
				((long)(thePlayer.zPos) * (long)(thePlayer.zPos));
	}
	else if (theOpponent.persona == kMissTeak)
	{
		oldDistSquared = ((long)(theOpponent.xPos) * (long)(theOpponent.xPos)) + 
				((long)(theOpponent.zPos) * (long)(theOpponent.zPos));
	}
	
	UpdateBallTimers(&thePlayer);
	UpdateBallTimers(&theOpponent);
	UpdateArrows();
}


//========================================================  DoAFoul  

void DoAFoul (void)

{
	if (theBall.modifier == kPlayerLastHeld)
		HandlePlayerFoul();
	else
		HandleOpponentFoul();
	
	theBall.eraseTheBall = TRUE;
	ResetBall();
}


//========================================================  DoBallFiring  

void DoBallFiring (void)

{
	theBall.modifier--;
	if (theBall.modifier == 0)
	{
		PlaySoundSMS(kBallFiringSound);
		
		theBall.mode = kBallRolling;
		theBall.modifier = kNoOneLastHeld;
		theBall.loopsBallIdle = kLoopLimitOnIdleBall;
		
		theDoor.doorState = kDoorIsOpen;
		theDoor.phase = kDoorPhases;
		theDoor.stateChanged = TRUE;
		if (leftScoredLast)
			theDoor.doorOpen = kLeftDoor;
		else
			theDoor.doorOpen = kRightDoor;
		
		whosGotBall = kBallRollsFreely;
	}
}


//========================================================  MoveRollingBall  

void MoveRollingBall (void)

{
	#define			kOffTheDishLg	473497600L	// 340 x 64 ^2 
	#define			kOffTheDishSm	321126400L	// 280 x 64 ^2 
	long			ballDistSquared;
	short			indexX, indexZ;
	short			signX, signZ;
	short			forceX, forceZ;
	short			frictionX, frictionZ;
	short			tempVel;
	
	indexX = theBall.xPos;
	if (indexX < 0)
	{
		indexX = -indexX;
		signX = -1;
	}
	else
	{
		signX = 1;
	}
	indexX /= 512;
	
	indexZ = theBall.zPos;
	if (indexZ < 0)
	{
		indexZ = -indexZ;
		signZ = -1;
	}
	else
	{
		signZ = 1;
	}
	indexZ /= 512;
	
	if (theBall.xPos < 0)
	{
		switch (leftGoalLeague)
		{
			case kLittleLeague:
				forceX = *(littleForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kJuniorVarsity:
				forceX = *(juniorForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kVarsity:
				forceX = *(varsityForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kMinorLeague:
				forceX = *(minorForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kProfessional:
				forceX = *(proForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			default:
				forceX = 0;
				break;
		}
	}
	else
	{
		switch (rightGoalLeague)
		{
			case kLittleLeague:
				forceX = *(littleForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kJuniorVarsity:
				forceX = *(juniorForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kVarsity:
				forceX = *(varsityForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kMinorLeague:
				forceX = *(minorForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			case kProfessional:
				forceX = *(proForceTable + indexX * 82 + indexZ * 2 + kXComponent);
				break;
			default:
				forceX = 0;
				break;
		}
	}
	
	switch (forceX)
	{
		case kOutOBounds:
			theBall.flag = kIsOutOfBounds;
			break;
		case kBackBoard:
			if (theBall.zPos < 0)
				theBall.flag = kIsOutOfBounds;
			else
			{
				HandleBallWallCollision();
				theBall.xPos += (theBall.xVel / kVelocitySensitive);
				theBall.zPos += (theBall.zVel / kVelocitySensitive);
			}
			break;
		case kGoalPath:
			if (theBall.zPos < 0)
				theBall.flag = kIsOutOfBounds;
			else
				theBall.flag = kIsInGoal;
			break;
		default:
			theBall.flag = kIsNormal;
			forceX *= signX;
			
			if (theBall.xPos < 0)
			{
				switch (leftGoalLeague)
				{
					case kLittleLeague:
						forceZ = *(littleForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kJuniorVarsity:
						forceZ = *(juniorForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kVarsity:
						forceZ = *(varsityForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kMinorLeague:
						forceZ = *(minorForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kProfessional:
						forceZ = *(proForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					default:
						forceZ = 0;
						break;
				}
			}
			else
			{
				switch (rightGoalLeague)
				{
					case kLittleLeague:
						forceZ = *(littleForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kJuniorVarsity:
						forceZ = *(juniorForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kVarsity:
						forceZ = *(varsityForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kMinorLeague:
						forceZ = *(minorForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					case kProfessional:
						forceZ = *(proForceTable + indexX * 82 + indexZ * 2 + 
								kZComponent) * signZ;
						break;
					default:
						forceZ = 0;
						break;
				}
			}
			
			theBall.xVel -= forceX;
			theBall.zVel -= forceZ;
			
			if (theBall.justHitWall == 0)
			{
				frictionX = theBall.xVel / kFrictionFraction;
				frictionZ = theBall.zVel / kFrictionFraction;
				theBall.xVel -= frictionX;
				theBall.zVel -= frictionZ;
			}
			
			theBall.xPos += (theBall.xVel / kVelocitySensitive);
			theBall.zPos += (theBall.zVel / kVelocitySensitive);
			break;
	}
	
	ballDistSquared = ((long)theBall.xPos * (long)theBall.xPos) + 
			((long)theBall.zPos * (long)theBall.zPos);
	
	if (arenaSize == kLargeArena)
	{
		if (ballDistSquared > kOffTheDishLg)
			theBall.dontDraw = TRUE;
		else
			theBall.dontDraw = FALSE;
	}
	else
	{
		if (ballDistSquared > kOffTheDishSm)
			theBall.dontDraw = TRUE;
		else
			theBall.dontDraw = FALSE;
	}
	
	BallRectFromPosition();
}


//========================================================  DoBallInGoal  

void DoBallInGoal (void)

{
	theBall.eraseTheBall = TRUE;
	
	if (theBall.xPos < 0)
	{
		if (leftGoalIsPlayers)
			DoPlayerScores();
		else
			DoOpponentScores();
	}
	else
	{
		if (!leftGoalIsPlayers)
			DoPlayerScores();
		else
			DoOpponentScores();
	}
	
	ResetBall();
}


//========================================================  DoBallRolling  

void DoBallRolling (void)

{
	switch (theBall.flag)
	{
		case kIsNormal:
		case kIsRebounding:
			MoveRollingBall();
			theBall.loopsBallIdle--;
			if (theBall.loopsBallIdle == 120)
			{
				PlaySoundSMS(kIdleSound);
			}
			if (theBall.loopsBallIdle == 0)
			{
				theBall.eraseTheBall = TRUE;
				ResetBall();
			}
			break;
		case kIsOutOfBounds:
			DoAFoul();
			break;
		case kIsInGoal:
			DoBallInGoal();
			break;
		default:
			break;
	}
}


//========================================================  HandleBall  

void HandleBall (void)

{
	switch (theBall.mode)
	{
		case kBallFiring:
			DoBallFiring();
			break;
		case kBallRolling:
			DoBallRolling();
			break;
		case kBallHeld:
			break;
		case kBallInStasis:
			break;
	}
	
	if (theDoor.phase != 0)
	{
		theDoor.phase--;
		if (theDoor.phase == 0)
		{
			theDoor.doorState = kDoorIsClosed;
			theDoor.stateChanged = TRUE;
		}
	}
}


