
#include "MW4Headers.hpp"

#include "ClusterBombWeapon.hpp"
#include "Missile.hpp"
#include "MWObject.hpp"
#include "SubsystemClassData.hpp"
#include "Torso.hpp"

#include <Adept\Map.hpp>
#include <Adept\Site.hpp>
#include <MLR\MLRTexturePool.hpp>

//#############################################################################
//############################  ClusterBombWeaponSubsystem    #####################
//#############################################################################

ClusterBombWeaponSubsystem::ClassData*
	ClusterBombWeaponSubsystem::DefaultData = NULL;

YawPitchRoll* ClusterBombWeaponSubsystem::m_clusterVectors [ClusterCycle];

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ClusterBombWeaponSubsystem::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ClusterBombWeaponSubsystemClassID,
			"MechWarrior4::ClusterBombWeaponSubsystem",
			MissileWeapon::DefaultData,
			0, NULL,
			(Entity::Factory)Make,
			(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
			ExecutionStateEngine::DefaultData,
			(Entity::GameModel::Factory)GameModel::ConstructGameModel,
			NULL,
			(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
			(Entity::GameModel::ModelWrite)GameModel::WriteToText,
			(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
			(Subsystem::StreamCreate) CreateStream
		);
	Register_Object(DefaultData);

	m_clusterVectors [0] = new YawPitchRoll (-1.5,0.0,0.0);
	m_clusterVectors [1] = new YawPitchRoll (1.5 ,0.0,0.0);
	m_clusterVectors [2] = new YawPitchRoll (0.0 ,0.0,-1.5);
	m_clusterVectors [3] = new YawPitchRoll (0.0 ,0.0,1.5);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ClusterBombWeaponSubsystem::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
	
	for ( int i =0; (i< ClusterCycle); i++)
	{
		delete m_clusterVectors[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ClusterBombWeaponSubsystem*
	ClusterBombWeaponSubsystem::Make(
		CreateMessage *message,
		ReplicatorID *base_id
	)
{
	Check_Object(message);
	gos_PushCurrentHeap(Heap);
	ClusterBombWeaponSubsystem *new_entity =
		new ClusterBombWeaponSubsystem(DefaultData, message, base_id, NULL);
	gos_PopCurrentHeap();
	Check_Object(new_entity);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ClusterBombWeaponSubsystem::ClusterBombWeaponSubsystem(
	ClassData *class_data,
	CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	MissileWeapon(class_data, message, base_id, element)
{
	m_clusterInc =0;
	Check_Pointer(this);
	Check_Object(message);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ClusterBombWeaponSubsystem::~ClusterBombWeaponSubsystem()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	ClusterBombWeaponSubsystem::CreateProjectile(Time till)
{
	Check_Object(this);
	const GameModel *model = GetGameModel();
	Check_Object(model);

	if(model->projectileModelResource != ResourceID::Null)
	{
		
		//
		//---------------------------------
		//Get the ClassID from the Resource
		//---------------------------------
		//
		ClassID class_ID;
		class_ID = GetClassIDFromDataListID(model->projectileModelResource);
		Verify(class_ID != NullClassID);

		ReplicatorID site_id = ReplicatorID::Null;
		Normal3D target_normal;

		Motion3D initial_velocity = Motion3D::Identity;
		Motion3D initial_acceleration = Motion3D::Identity;

		//
		//-----------------------------------------
		//We need to get the forward of the eyesite
		//-----------------------------------------
		//
		
		
	

		UnitVector3D direction;

		
		if (GetParentVehicle()->GetTorso() != 0)
		{
			//GetParentVehicle()->GetTorso()->GetTwistJointMatrix().GetLocalForwardInWorld(&direction);

			LinearMatrix4D pitch_matrix = LinearMatrix4D::Identity;
			//pitch_matrix.BuildRotation(YawPitchRoll(GetParentVehicle()->GetTorso()->yawValue, GetParentVehicle()->GetTorso()->pitchValue, 0.0f));
			switch (m_clusterInc)
			{
				case 0:
					pitch_matrix.BuildRotation(YawPitchRoll(GetParentVehicle()->GetTorso()->yawValue -0.1f, GetParentVehicle()->GetTorso()->pitchValue, 0.0f));
				break;
				case 1:
					pitch_matrix.BuildRotation(YawPitchRoll(GetParentVehicle()->GetTorso()->yawValue +0.1f, GetParentVehicle()->GetTorso()->pitchValue, 0.0f));
				break;
				case 2:
					pitch_matrix.BuildRotation(YawPitchRoll(GetParentVehicle()->GetTorso()->yawValue, GetParentVehicle()->GetTorso()->pitchValue -0.05f, 0.0f));
				break;
				case 3: 
					pitch_matrix.BuildRotation(YawPitchRoll(GetParentVehicle()->GetTorso()->yawValue, GetParentVehicle()->GetTorso()->pitchValue + 0.05f, 0.0f));
				break;
			}

			//UnitVector3D temp_direction;
			//GetParentVehicle()->GetLocalToWorld().GetLocalForwardInWorld(&temp_direction);

			//direction.Multiply(temp_direction, pitch_matrix);
	
			LinearMatrix4D direction_mat;

			direction_mat.Multiply(pitch_matrix, GetParentVehicle()->GetLocalToWorld());

			//SPEWALWAYS(("jerryeds", "%f %f %f", temp_direction.x, temp_direction.y, temp_direction.z));


			direction_mat.GetLocalForwardInWorld(&direction);

		}
		else
		{
			GetParentVehicle()->GetLocalToWorld().GetLocalForwardInWorld(&direction);
		}
	

		
		switch (m_clusterInc)
		{
			case 0:
			case 1:
				initial_velocity.linearMotion.Multiply(
					model->initialLinearVelocity,
					direction);
			break;
			case 2:
				initial_velocity.linearMotion.Multiply(
					Vector3D ( model->initialLinearVelocity.x,
					model->initialLinearVelocity.y -25.0f,
					model->initialLinearVelocity.z), direction);					
			break;
			case 3:
				initial_velocity.linearMotion.Multiply(
					Vector3D ( model->initialLinearVelocity.x,
					model->initialLinearVelocity.y +50.0f,
					model->initialLinearVelocity.z), direction);					
			break;
		}


		initial_acceleration.linearMotion.x = 0.0f;
		initial_acceleration.linearMotion.y = -g_Gravity;
		initial_acceleration.linearMotion.z = 0.0f;






		ReplicatorID target_id;
		target_id = ReplicatorID::Null;
		Point3D target_point;
		//
		//------------------------------------
		//Create the Missile CreateMessage
		//------------------------------------
		//
		

		m_clusterInc = (m_clusterInc +1)%ClusterCycle;

		



		WeaponMover::CreateMessage projectile_create_message(
			sizeof(Missile::CreateMessage),
			DefaultEventPriority,
			CreateMessage::DefaultFlags,
			class_ID,
			WeaponMover::DefaultFlags,
			model->projectileModelResource,
			sitePointer->GetLocalToWorld(),
			0.0f,
			WeaponMover::ExecutionStateEngine::LinearDragMotionState,
			NameTable::NullObjectID,
			Entity::DefaultAlignment,
			initial_velocity,
			initial_acceleration,
			model->damageAmount,
			model->heatToDeal,
			model->maxDistance,
// MSL 5.03 Min Distance
//			model->minDistance,
			GetParentVehicle()->GetReplicatorID(),
			model->splashRadius,
			model->percentageOfDamageToDirectHit,
			model->minPercentageOfDamageToSphereHit,
			model->maxPercentageOfDamageToSphereHit,
			model->itemID
		);
		MemoryStream stream(&projectile_create_message, projectile_create_message.messageLength);

		Entity *entity;
		ReplicatorID projectile_id = Connection::Hermit->GetNextReplicatorID();
		entity = CreateEntity(&stream, &projectile_id, false);
		Check_Object(entity);
		Map::GetInstance()->AddChild(entity);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
	ClusterBombWeaponSubsystem::GetDistanceWithAngle(Scalar angle)
{
	Check_Object(this);

	const GameModel *model = GetGameModel();
	Check_Object(model);

	if(angle < 0.0f)
		return 0.0f;

	Scalar muzzle = model->initialLinearVelocity.y;
	Scalar value;
	angle *= angle;
	Scalar temp = angle * angle;
	value = 2 * muzzle * muzzle * (Sqrt(Fabs(angle - temp)));
	value /= g_Gravity;

	return value;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ClusterBombWeaponSubsystem::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

