//============================================================
//============================================================
//==														==
//==			Common Person Handling Routines				==
//==														==
//============================================================
//============================================================


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

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


//========================================================  Functions  
//========================================================  PersonRectFromPosition  

void PersonRectFromPosition (playerType *who)

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


//========================================================  ResetPerson  

void ResetPerson (playerType *who)

{
	if (who->selector == kPlayerSelector)
	{
		who->dirFlagSrc = kFacingRested;
		who->postFlagSrc = kStanding;
		
		who->arrayFlagMask = kFadeMask;
		who->dirFlagMask = fadeMaskSequence[0];
		who->postFlagMask = kStanding;
	}
	else
	{
		who->dirFlagSrc = kFacingRested;
		who->postFlagSrc = kStanding;
		
		who->arrayFlagMask = kFadeMask;
		who->dirFlagMask = fadeMaskSequence[0];
		who->postFlagMask = kStanding;
	}
	
	who->xPos = who->initXPos;
	who->zPos = who->initZPos;
	
	who->xVel = 0;
	who->zVel = 0;
	who->direction = kFacingRested;
	who->mode = kInStasis;
	who->posture = kStanding;
	who->flag = kLengthOfPenalty;
	who->justHitWall = 0;
	who->justHitBall = 0;
	who->justHitOpponent = 0;
	who->loopsBallHeld = 0;
	who->brakeApplied = FALSE;
	who->bashApplied = FALSE;
	
	if ((who->persona == kHumanPlayer) || (who->persona == kNetHuman))
		who->mouseWasLetUp = TRUE;
	
	PersonRectFromPosition(who);
}


//========================================================  StartPersonBeamOut  

void StartPersonBeamOut (playerType *who)

{
	PlaySoundSMS(kBeamOutSound);
	who->mode = kBeamingOut;
	who->flag = 0;
}


//========================================================  MovePerson  

void MovePerson (playerType *who)

{
	short			indexX, indexZ;
	short			signX, signZ;
	short			forceX, forceZ;
	short			frictionX, frictionZ;
	
	indexX = who->xPos;
	if (indexX < 0)
	{
		indexX = -indexX;
		signX = -1;
	}
	else
	{
		signX = 1;
	}
	indexX /= 512;
	
	indexZ = who->zPos;
	if (indexZ < 0)
	{
		indexZ = -indexZ;
		signZ = -1;
	}
	else
	{
		signZ = 1;
	}
	indexZ /= 512;
	
	if (who->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:
			who->flag = kIsOutOfBounds;
			break;
		case kGoalPath:
		case kBackBoard:
			if (who->zPos < 0)
			{
				who->flag = kIsOutOfBounds;
			}
			else
			{
				HandlePersonWallCollision(who);
				
				who->xPos += (who->xVel / kVelocitySensitive);
				who->zPos += (who->zVel / kVelocitySensitive);
			}
			break;
		default:
			who->flag = kIsNormal;
			forceX *= signX;
			
			if (who->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;
				}
			}
			
			who->xVel -= forceX;
			who->zVel -= forceZ;
			
			if (who->justHitWall == 0)
			{
				frictionX = who->xVel / kFrictionFraction;
				frictionZ = who->zVel / kFrictionFraction;
				who->xVel -= frictionX;
				who->zVel -= frictionZ;
			}
			
			who->xPos += (who->xVel / kVelocitySensitive);
			who->zPos += (who->zVel / kVelocitySensitive);
			break;
	}
	
	PersonRectFromPosition(who);
}


//========================================================  OpponentDecides  

void OpponentDecides (playerType *who)

{
	switch (who->persona)
	{
		case kSimpleGeorge:
			GeorgeDecides(who);
			break;
		case kMadMara:
			MaraDecides(who);
			break;
		case kHeavyOtto:
			OttoDecides(who);
			break;
		case kCleverClaire:
			ClaireDecides(who);
			break;
		case kMisterEaze:
			EazeDecides(who);
			break;
		case kMissTeak:
			TeakDecides(who);
			break;
		case kNetHuman:
			DetermineHumanFacing(who);
			ProcessNetPlayerInput();
			break;
		default:
			break;
	}
}


//========================================================  DoPersonInArena  

void DoPersonInArena (playerType *who)

{
	switch (who->flag)
	{
		case kIsNormal:
		case kIsRebounding:
			if (who->persona == kHumanPlayer)
			{
				DetermineHumanFacing(who);
				GetHumanInput();
			}
			else
			{
				OpponentDecides(who);
			}
			MovePerson(who);
			break;
		case kIsOutOfBounds:
			if ((theBall.modifier == kPlayerHolding) && 
					(who->selector == kPlayerSelector))
			{
				HandlePlayerFoul();
				ResetBall();
			}
			else if ((theBall.modifier == kOpponentHolding) && 
					(who->selector == kOpponentSelector))
			{
				HandleOpponentFoul();
				ResetBall();
			}
			StartPersonBeamOut(who);
			break;
	}
	
	if (((theBall.modifier == kPlayerHolding) && (who->selector == kPlayerSelector)) ||
			((theBall.modifier == kOpponentHolding) && 
			(who->selector == kOpponentSelector)))
	{
		if (who->loopsBallHeld != 0)
		{
			who->loopsBallHeld--;
			
			UpdateBallTimers(who);
			
			if (who->loopsBallHeld == 120)
			{
				PlaySoundSMS(kHoldingSound);
			}
			else if (who->loopsBallHeld == 0)
			{
				if (whosGotBall == kPlayerHasBall)
				{
					HandlePlayerFoul();
				}
				else
				{
					HandleOpponentFoul();
				}
				theBall.eraseTheBall = TRUE;
				ResetBall();
			}
		}
	}
		
	if (who->selector == kPlayerSelector)
	{
		who->dirFlagSrc = who->direction;
		who->postFlagSrc = who->posture;
		
		who->arrayFlagMask = kMask;
		who->dirFlagMask = who->direction;
		who->postFlagMask = who->posture;
	}
	else
	{
		who->dirFlagSrc = who->direction;
		who->postFlagSrc = who->posture;
		
		who->arrayFlagMask = kMask;
		who->dirFlagMask = who->direction;
		who->postFlagMask = who->posture;
	}
}


//========================================================  DoPersonBeamingIn  

void DoPersonBeamingIn (playerType *who)

{
	who->flag--;
	if (who->flag < 0)				// person has fully faded in 
	{
		who->mode = kInArena;
		who->flag = kIsNormal;
		if (who->selector == kPlayerSelector)
		{
			who->dirFlagSrc = who->direction;
			who->postFlagSrc = who->posture;
			
			who->arrayFlagMask = kMask;
			who->dirFlagMask = who->direction;
			who->postFlagMask = who->posture;
		}
		else
		{
			who->dirFlagSrc = who->direction;
			who->postFlagSrc = who->posture;
			
			who->arrayFlagMask = kMask;
			who->dirFlagMask = who->direction;
			who->postFlagMask = who->posture;
		}
	}
	else							// person is still fading in 
	{
		if (who->selector == kPlayerSelector)
		{
			who->dirFlagSrc = kFacingRested;
			who->postFlagSrc = who->posture;
			
			who->arrayFlagMask = kFadeMask;
			who->dirFlagMask = fadeMaskSequence[who->flag];
			who->postFlagMask = who->posture;
		}
		else
		{
			who->dirFlagSrc = kFacingRested;
			who->postFlagSrc = who->posture;
			
			who->arrayFlagMask = kFadeMask;
			who->dirFlagMask = fadeMaskSequence[who->flag];
			who->postFlagMask = who->posture;
		}
	}
}


//========================================================  DoPersonBeamingOut  

void DoPersonBeamingOut (playerType *who)

{
	who->flag++;
	if (who->flag > kEndOfFadeSequence)	// person has fully faded out 
	{
		drawThisFrame = TRUE;
		who->flag = kEndOfFadeSequence;
		ResetPerson(who);
	}
	else
	{
		if (who->flag == kEndOfFadeSequence)
			drawThisFrame = TRUE;
		
		if (who->selector == kPlayerSelector)
		{
			who->dirFlagSrc = kFacingRested;
			who->postFlagSrc = who->posture;
			
			who->arrayFlagMask = kFadeMask;
			who->dirFlagMask = fadeMaskSequence[who->flag];
			who->postFlagMask = who->posture;
		}
		else
		{
			who->dirFlagSrc = kFacingRested;
			who->postFlagSrc = who->posture;
			
			who->arrayFlagMask = kFadeMask;
			who->dirFlagMask = fadeMaskSequence[who->flag];
			who->postFlagMask = who->posture;
		}
	}
}


//========================================================  PersonStasisToBeamIn  

void PersonStasisToBeamIn (playerType *who)

{
	PlaySoundSMS(kBeamInSound);
	
	who->mode = kBeamingIn;
	who->flag = kEndOfFadeSequence;
	
	if (who->selector == kPlayerSelector)
	{
		who->dirFlagSrc = kFacingRested;
		who->postFlagSrc = who->posture;
		
		who->arrayFlagMask = kFadeMask;
		who->dirFlagMask = fadeMaskSequence[who->flag];
		who->postFlagMask = who->posture;
	}
	else
	{
		who->dirFlagSrc = kFacingRested;
		who->postFlagSrc = who->posture;
		
		who->arrayFlagMask = kFadeMask;
		who->dirFlagMask = fadeMaskSequence[who->flag];
		who->postFlagMask = who->posture;
	}
}


//========================================================  DoPersonInStasis  

void DoPersonInStasis (playerType *who)

{
	who->flag--;
	if (who->flag < 1)
		PersonStasisToBeamIn(who);
}



//========================================================  HandlePerson  

void HandlePerson (playerType *who)

{
	switch (who->mode)
	{
		case kInArena:
			DoPersonInArena(who);
			break;
		case kBeamingIn:
			DoPersonBeamingIn(who);
			break;
		case kBeamingOut:
			DoPersonBeamingOut(who);
			break;
		case kInStasis:
			DoPersonInStasis(who);
			break;
	}
}


