/*
*	simulation.cpp
*	----------------------------------------
*	A part of "Intelligent AI"
*	© 2001 SCC Team 064
*	----------------------------------------
*
*	This file:
*		€ Runs the simulation loop (calling AI functions and continuously-called
*		   general functions in sequence).
*		€ Contains any functions that are utilized by the Simulation to affect the planes.
*/

#include "Project.h"
#include "MacInput.h"



/*										Run Simulation										*/
/*------------------------------------------------------------------------------------------*/
/*
*	This function calls all simulation functions sequentially in a continual loop, where each loop
*	is a "turn" in which each player can make decisions for moving/attacking units
*	and events allready in action continue to be carried out.
*/
void runSimulation()
{
	int playerAIType;
	int currentNumPlayers = getCurrentNumPlayers();

	if (currentNumPlayers > 1)
	{
		for (int i = 0; i < currentNumPlayers; i++)
		{
			playerAIType = getAIType(i);

			switch (playerAIType)
			{
				case constantAI:
					ConstantAI(i);
					break;

				case evolvingAI:
					EvolvingAI(i);
					break;

				case humanAI:
					HumanAI(i);
					break;
			}
		}

		PlayerElimination();
	}
	else
		pDone = true;
}



/*------------------------------------------------------------------------------------------*/
/*										SIMULATION FUNCTIONS								*/
/*------------------------------------------------------------------------------------------*/



/*										Continue Moving										*/
/*------------------------------------------------------------------------------------------*/
/* 
* This function executes the actual moving of a plane through space, through resolving force vectors.
*/
void player_class::ContinueMoving()
{
	double			dragX, dragY, dragZ, appliedThrust, lift, weight;
	double			netAccelX, netAccelY, netAccelZ;
	double			speed;

	if ((yaw) >= 2. * M_PI)
		yaw -= (2. * M_PI);
	if ((yaw) < 0)
		yaw += (2. * M_PI);
	if ((pitch) >= 2. * M_PI)
		pitch -= (2. * M_PI);
	if ((pitch) < 0)
		pitch += (2. * M_PI);

	// Calculates speed of the plane in direction of travel. (essentialy speed of the 
	// air over the wing.
	speed = ((speedX * cos(pitch) * cos(yaw)) + (speedY * cos(pitch) * sin(yaw)) + 
							(speedZ * sin(pitch) * cos(yaw)));

	// Thrust Vector
	appliedThrust = thrust;

	// Drag Vector in each axis of movement
	dragX = dragCoef * ( speedX * speedX );
	dragY = dragCoef * ( speedY * speedY );
	dragZ = dragCoef * ( speedZ * speedZ );

	// Ensures that the Drag vector is always opposite the Trust vector
	if (speedX < 0)
		dragX = -dragX;
	if (speedY < 0)
		dragY = -dragY;
	if (speedZ < 0)
		dragZ = -dragZ;

	// Eliminates the problem of the system beeing too accurate. These variables sometimes need to
	// be zero, not almost zero.
	if((dragX < .0000000000000001) && (dragX > -.0000000000000001))
		dragX = 0;
	if((dragY < .0000000000000001) && (dragY > -.0000000000000001))
		dragY = 0;
	if((dragZ < .0000000000000001) && (dragZ > -.0000000000000001))
		dragZ = 0;

	//Weight Vector, always straight down
	weight = mass * gravity;

	//Lift Vector   IN RELATION TO SPEED AND ALTITIUDE
	lift[0] = liftCoef * ( speed );
//	lift = weight;

	lift[1] = pitch + M_PI / 2.;
	lift[2] = roll + M_PI / 2.;

	// Rounds lift to zero when neccessary.
	if((lift < .0000000000000001) && (lift > -.0000000000000001))
		lift = 0;

	// Calculating the Net Accelerations in each diretion to find out where in space the ship should be
	netAccelX = ( (appliedThrust) * cos(pitch) * cos(yaw) + dragX + lift * sin(pitch) * sin(yaw) ) / mass;
	netAccelY = ( (appliedThrust) *cos(pitch) * sin(yaw) + dragY + lift * sin(pitch) * cos(yaw) ) / mass;
	netAccelZ = ((appliedThrust) * sin(pitch) + dragZ + lift * cos(pitch) * cos(roll) - weight) / mass;

	// Adds the acceleration of the plane to its original speed.
	speedX += netAccelX;
	speedY += netAccelY;
	speedZ += netAccelZ;


	//Move Units - generates the new X, Y, and Z positions of the planes.
	xPos	+= speedX *.00015;
	yPos	+= speedY *.00015;
	zPos	+= speedZ *.00015;
}


/*										Collision Detection									*/
/*------------------------------------------------------------------------------------------*/
/* 
* This function ensures that no two units occupy the same coordinate square.  If they do, the 
* function destroys both players, and declares both the looser.  To do this, it checks the planes
* positions against eachother.
*/
void player_class::CollisionDetection(player_class &enemy)
{
	if (xPos == enemy.xPos && yPos == enemy.yPos && zPos == enemy.zPos)
	{
		hitPoints = 0;
		enemy.hitPoints = 0;
	}
}


/*										Player Elimination									*/
/*------------------------------------------------------------------------------------------*/
/* 
* Utalizes a number corresponding with a unit in gameplay, and a number corresponding with 
* the player the unit belongs to, to check to see if any planes have lost all of their hitPoints,  
* and, if so, elimates them from the simulation.
*/
void PlayerElimination()
{
	int currentNumPlayers;

	for (int i = 0; i < getCurrentNumPlayers(); i++)
	{
		if (player[i].hitPoints <= 0)
		{
			player[i].~player_class();					//Destroy Player i

			currentNumPlayers = getCurrentNumPlayers() - 1;
			storeCurrentNumPlayers(currentNumPlayers);
		}
	}
}