//===========================================================================//
// File:	Missile.cpp											
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 09/09/98  JSE  Inital base class based off of Shadowrun/Adept             //
// 09/25/98  BDB  WeaponMover based on Vehicle								 //
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "MW4Headers.hpp"

#include "Missile.hpp"
#include "Vehicle.hpp"
#include "Decal.hpp"
#include "VehicleInterface.hpp"
#include "MWMission.hpp"
#include "MWDamageObject.hpp"

#include <Adept\Map.hpp>
#include <Adept\Effect.hpp>
#include <Adept\NameTable.hpp>
#include <Adept\EntityManager.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\CollisionVolume.hpp>

//#define MISSILE_BUG "johnyo"
//#define MISSILE_BUG "daberger"
//#define TARGET_BUG "daberger"

//#############################################################################
//##########################    ExecutionStateEngine    #######################
//#############################################################################

Missile::ExecutionStateEngine::ClassData*
	Missile::ExecutionStateEngine::DefaultData = NULL;

DWORD MechWarrior4::Executed_Missile_Count = 0;

const StateEngine::StateEntry
	Missile::ExecutionStateEngine::StateEntries[]=
{
	STATE_ENTRY(Missile__ExecutionStateEngine, LRMMotion),
	STATE_ENTRY(Missile__ExecutionStateEngine, MRMMotion),
	STATE_ENTRY(Missile__ExecutionStateEngine, SRMMotion),
	STATE_ENTRY(Missile__ExecutionStateEngine, SSRMMotion),
	STATE_ENTRY(Missile__ExecutionStateEngine, BombMotion),
	STATE_ENTRY(Missile__ExecutionStateEngine, LongTomMotion)

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::ExecutionStateEngine::InitializeClass()
{
	Check_Object(StateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			Missile__ExecutionStateEngineClassID,
			"Missile::ExecutionStateEngine",
			BaseClass::DefaultData,
			ELEMENTS(StateEntries), StateEntries,
			(Entity::ExecutionStateEngine::Factory)Make,
			(Entity::ExecutionStateEngine::FactoryRequest::Factory)
				&FactoryRequest::ConstructFactoryRequest
		);
	Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::ExecutionStateEngine::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Missile::ExecutionStateEngine*
	Missile::ExecutionStateEngine::Make(
		Missile *weapon,
		FactoryRequest *request
	)
{
	Check_Object(weapon);
	Check_Object(request);
	gos_PushCurrentHeap(Heap);
	Missile::ExecutionStateEngine *engine =
		new Missile::ExecutionStateEngine(DefaultData, weapon, request);
	gos_PopCurrentHeap();
	return engine;
		
}

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

//#############################################################################
//###############################    Missile    ###############################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Missile::ClassData*
	Missile::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::InitializeClass()
{
	Check_Object(Missile::ExecutionStateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MissileClassID,
			"MechWarrior4::Missile",
			BaseClass::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
		);
	Register_Object(DefaultData);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Missile__GameModel,
		MaxTurnAngle,
		maxTurnAngle,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Missile__GameModel,
		ThrusterAcceleration,
		thrusterAcceleration,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Missile__GameModel,
		ProximityFuseDistance,
		proximityFuseDistance,
		Scalar
	);

	DIRECT_GAME_MODEL_ATTRIBUTE(
		Missile__GameModel,
		MaxLiveTime,
		maxLiveTime,
		Scalar
	);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Missile*
	Missile::Make(
		CreateMessage *message,
		ReplicatorID *base_id
	)
{
	Check_Object(message);
	gos_PushCurrentHeap(Heap);
	Missile *new_entity;
	Entity *entity = EntityManager::GetInstance()->RequestFromArmory(message->dataListID);
	if (entity)
	{
		new_entity = Cast_Object(Missile*, entity);
		new_entity->Reuse(message, base_id);
	}
	else
		new_entity = new Missile(DefaultData, message, base_id, NULL);
	gos_PopCurrentHeap();
	Check_Object(new_entity);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Missile::Missile(
	ClassData *class_data,
	CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	WeaponMover(class_data, message, base_id, element),
	targetEntity(NULL),
	targetMWObject(NULL)
{
	Check_Pointer(this);
	Check_Object(message);
	targetEntity.Remove();
	
	targetOffsetFromEntity.x = 0.0f;
	targetOffsetFromEntity.y = 0.0f;
	targetOffsetFromEntity.z = 0.0f;

	targetPoint = message->targetPoint;
	burnTime = message->burnTime;

	if(message->targetID != ReplicatorID::Null)
	{
		Check_Object(Network::GetInstance());
		Connection	*connection = Network::GetInstance()->GetConnection(message->targetID.connectionID);
		if (connection)
		{
			Check_Object(connection);

			Replicator *replicator;
			replicator = connection->FindReplicator(message->targetID);
			if (replicator)
			{
				Check_Object(replicator);
				targetEntity.Remove();
				targetEntity.Add(Cast_Object(Entity*, replicator));

				//
				// This won't account for rotation. I'm not sure how well this will work on a component that can rotate, since I
				// don't have a full transform to get to this point.
				//
				// only in the case of a locked entity, is targetPoint relative to the entity
				targetOffsetFromEntity = targetPoint;


				Stuff::Point3D tempPoint3D = targetPoint;
				targetPoint.Multiply(tempPoint3D, targetEntity.GetCurrent()->GetLocalToWorld());



				Entity * parentEntity = TraceToParent(targetEntity.GetCurrent());

				targetMWObject.Remove();
				if(parentEntity && parentEntity->IsDerivedFrom(MWObject::DefaultData))
					targetMWObject.Add(Cast_Object(MWObject*, parentEntity));

				if(targetMWObject.GetCurrent())
				{
					targetMWObject.GetCurrent()->NotifyOfMissileLock();
				}
			}
		}
	}
	
	targetPosition = targetPoint;

	timeInAir = 0.0f;


	m_fAllowArcMissile = true;
	m_fTurnOffSeek = false;
	m_nMissCount = 0;

	srmPitchVector.x = 0.0f;
	srmPitchVector.y = -0.6f;
	srmPitchVector.z = 0.8f;

	srmYTargetOffset = 0.0f;

	doesAMSDestroyThisFrame = false;
	amsExplosionResource = ResourceID::Null;

  //
  // We are going to store this to fix the odd angles when frame rate dips
  //
  lastWorldSpaceVelocity = initialWorldSpaceVelocity;

  m_nDoubleTeleportPreventor = 0;
  GetTargetCollisionVolume();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Entity* Missile::GetFirstAcceptableParentEntity(Entity* entity)
{
  //
  // Walk up the chain looking for the next acceptable entity
  //
  Entity * curEntity = entity;
  while (curEntity)
  {

		if (!curEntity->IsDestroyed())
		{
			CollisionVolume *volume = curEntity->GetHierarchicalVolume();
			if (!volume)
			{
				volume = curEntity->GetSolidVolume();
			}
			if (volume)
			{
				//
				// This breaks if the volume above doesn't have anything at it's center since we can't guarantee this is
				// a valid local as we can with the original target passed in.
				//
			  targetOffsetFromEntity = volume->m_localSpaceBounds.localToParent;
				return curEntity;
			}

		}


    curEntity = curEntity->GetParentEntity();
  }
  return NULL;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Missile::GetTargetCollisionVolume()
{
  //
  // Walk up the chain looking for something with a collision volume
  //
  Entity * curEntity = targetEntity.GetCurrent();
  CollisionVolume *volume = NULL;
  while (curEntity)
  {
		volume = curEntity->GetHierarchicalVolume();
		if (!volume)
    {
      volume = curEntity->GetSolidVolume();
    }
		if (volume && !volume->IsDestroyed())
    {
      //
      // If we have a solid volume we should check for the first child.
      //
      CollisionVolume * childvolume = volume;
      //
      // Recurse down to the last node
      //
      while (childvolume)
      {
  		  ChainIteratorOf<CollisionVolume*> children(&childvolume->m_children);
        while ((childvolume = children.ReadAndNext()) != NULL)
        {
		      if (childvolume && !childvolume->IsDestroyed())
		      {
            volume = childvolume;
            childvolume = NULL; // to kick us out of here
            break;
          }
        }
      } // while childvolume



      break;

    }
    curEntity = curEntity->GetParentEntity();
  }
  target_collision_volume = volume;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Missile::~Missile()
{
	DESTRUCTOR("Missile");
	Check_Object(this);
	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::Reuse(
		const CreateMessage *message,
		ReplicatorID *base_id
	)
{
	Check_Pointer(this);
	Check_Object(message);

	BaseClass::Reuse(message, base_id);

	targetEntity.Remove();

	targetOffsetFromEntity.x = 0.0f;
	targetOffsetFromEntity.y = 0.0f;
	targetOffsetFromEntity.z = 0.0f;

	targetPoint = message->targetPoint;
	if(message->targetID != ReplicatorID::Null)
	{
		Check_Object(Network::GetInstance());
		Connection	*connection = Network::GetInstance()->GetConnection(message->targetID.connectionID);
		if (connection)
		{
			Check_Object(connection);

			Replicator *replicator;
			replicator = connection->FindReplicator(message->targetID);

			if (replicator)
			{
				Check_Object(replicator);
				targetEntity.Remove();
				targetEntity.Add(Cast_Object(Entity*, replicator));

				targetMWObject.Remove();

				//
				// This won't account for rotation. I'm not sure how well this will work on a component that can rotate, since I
				// don't have a full transform to get to this point.
				//
				// only in the case of a locked entity, is targetPoint relative to the entity
				targetOffsetFromEntity = targetPoint;

    
				Stuff::Point3D tempPoint3D = targetPoint;
				targetPoint.Multiply(tempPoint3D, targetEntity.GetCurrent()->GetLocalToWorld());

				Entity * parentEntity = TraceToParent(targetEntity.GetCurrent());

				targetMWObject.Remove();
				if(parentEntity && parentEntity->IsDerivedFrom(MWObject::DefaultData))
					targetMWObject.Add(Cast_Object(MWObject*, parentEntity));
			}
		}
	}

	targetPosition = targetPoint;
  timeInAir = 0.0f;

	m_fAllowArcMissile = true;
	m_fTurnOffSeek = false;
	m_nMissCount = 0;

	srmPitchVector.x = 0.0f;
	srmPitchVector.y = -0.6f;
	srmPitchVector.z = 0.8f;

	srmYTargetOffset = 0.0f;

  //
  // We are going to store this to fix the odd angles when frame rate dips
  //
  lastWorldSpaceVelocity = initialWorldSpaceVelocity;
  m_nDoubleTeleportPreventor = 0;
  GetTargetCollisionVolume();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::PreCollisionExecute(Stuff::Time till)
{
	Check_Object(this);
	PRECOLLISION_LOGIC("Missile");

	timeInAir += GetTimeSlice(till);
	const GameModel *model = GetGameModel();
	Check_Object(model);

	//
	//----------------------------------------------------
	// Make sure we use post collision and call our parent
	//----------------------------------------------------
	//
	Set_Statistic(Executed_Missile_Count, Executed_Missile_Count+1);
	BaseClass::PreCollisionExecute(till);

	//
	//-------------------------------
	// Apply the right type of forces
	//-------------------------------
	//
	Check_Object(executionState);
	int execution_state = executionState->GetState();
	switch(execution_state)
	{
	case ExecutionStateEngine::LRMMotionState:
		{
			LRMSeekerModel(till);
			SeekingThrusterSimulation(till);
			LinearDragMotionSimulation(till);
      ProximityCheck(till);
			break;
		}
	case ExecutionStateEngine::MRMMotionState:
		{
			MRMSeekerModel(till);
			SeekingThrusterSimulation(till);
			LinearDragMotionSimulation(till);
			break;
		}
	case ExecutionStateEngine::SRMMotionState:
		{
			SRMSeekerModel(till);	
			//
			// SRM's used to work like bullets with a fixed speed out of the gun. To make them behave more consistenly 
			// I am using the same code path as the others even though it is a little bit of overkill for their seek model.
			//
			SeekingThrusterSimulation(till);
			LinearDragMotionSimulation(till);
			break;
		}
	case ExecutionStateEngine::SSRMMotionState:
		{
			SSRMSeekerModel(till);
			SeekingThrusterSimulation(till);
			LinearDragMotionSimulation(till);
			break;
		}
	case ExecutionStateEngine::LongTomMotionState:
		{
			LongTomSeekerModel();
			SeekingThrusterSimulation(till);
			LinearDragMotionSimulation(till);
			break;
		}
	case ExecutionStateEngine::BombMotionState:
		{
			if(timeInAir >= model->maxLiveTime)
			{
				SentenceToDeathRow();
				return;
			}
			SRMSeekerModel(till);
			//
			// SRM's used to work like bullets with a fixed speed out of the gun. To make them behave more consistenly 
			// I am using the same code path as the others even though it is a little bit of overkill for their seek model.
			//
			SeekingThrusterSimulation(till);
			LinearDragMotionSimulation(till);
			break;
		}
	default:
		{
		//	STOP(("This is not a valid state for Missile"));
		}
	}
	//
	// If the missile is not a seeking missile or not locked, let it seek one frame to get direction
	// then stop seeking from the next frame on. Otherwise when it gets where it was
	// going, even non-locked, it will turn around and try to come back
	//
	if (!m_fTurnOffSeek && !targetEntity.GetCurrent() && Small_Enough(targetPoint.y - targetPosition.y))
	{
		Point3D local_direction;
		Point3D local_to_world_position;
		local_to_world_position = GetLocalToWorld();
		local_direction.Subtract(
			//targetPosition,
			targetPoint,
			local_to_world_position
		);

		UnitVector3D direction_to_target;
		Stuff::Scalar direction_to_target_length = local_direction.GetLengthSquared();
		if (Small_Enough(direction_to_target_length))
			{
				goto ExitFunction;
			}

		//
		// Normalize
		//
		direction_to_target_length = 1.0f / Sqrt(direction_to_target_length);
		direction_to_target.x = local_direction.x * direction_to_target_length;
		direction_to_target.y = local_direction.y * direction_to_target_length;
		direction_to_target.z = local_direction.z * direction_to_target_length;

		Stuff::Scalar differenceTargetAngleToPreviousVelocity;

		UnitVector3D current_direction;
		Stuff::Scalar current_direction_length = worldSpaceVelocity.linearMotion.GetLengthSquared();
		if (Small_Enough(current_direction_length))
			{
				goto ExitFunction;
			}

		//
		// Normalize
		//
		current_direction_length = 1.0f / Sqrt(current_direction_length);
		current_direction.x = worldSpaceVelocity.linearMotion.x * current_direction_length;
		current_direction.y = worldSpaceVelocity.linearMotion.y * current_direction_length;
		current_direction.z = worldSpaceVelocity.linearMotion.z * current_direction_length;

  
		differenceTargetAngleToPreviousVelocity = direction_to_target * current_direction;


		// If we are aimed close enough the target, and we are physically close enough, then just assume we are at the target

		if (differenceTargetAngleToPreviousVelocity >= 0.999f)
		{
			m_fTurnOffSeek = true;
			//
			// Aim right at the spot now
			//
			Point3D local_direction;
			Point3D local_to_world_position;
			local_to_world_position = GetLocalToWorld();
			local_direction.Subtract(
				targetPosition,
				local_to_world_position
			);
			LinearMatrix4D aligned_matrix = entityElement->GetNewLocalToParent();
			aligned_matrix.AlignLocalAxisToWorldVector(local_direction, Z_Axis, X_Axis, Y_Axis);
			SetNewLocalToParent(aligned_matrix);


			Stuff::Scalar linearMotionSpeed = localSpaceVelocity.linearMotion.GetApproximateLength();
			localSpaceVelocity.angularMotion.Zero();
			localSpaceVelocity.linearMotion.z = linearMotionSpeed;
			localSpaceVelocity.linearMotion.y = 0.0f;
			localSpaceVelocity.linearMotion.x = 0.0f;
			// reuse for acceleration
			linearMotionSpeed = localSpaceAcceleration.linearMotion.GetApproximateLength();
			localSpaceAcceleration.linearMotion.z = linearMotionSpeed;
			localSpaceAcceleration.linearMotion.y = 0.0f;
			localSpaceAcceleration.linearMotion.x = 0.0f;

				
			
			
//			localSpaceVelocity.angularMotion.Zero(); // make sure we don't end up in a spin when we stop orienting.
/*
			//
			// In order to preserve it's current acceleration, but make sure it hits the target we need to 
			// find the normalized direction that we want to go (
			//
			Stuff::Scalar current_acceleration_length = worldSpaceAcceleration.linearMotion.GetApproximateLength();
			worldSpaceAcceleration.linearMotion.Multiply(current_direction, current_acceleration_length);

			current_acceleration_length = localSpaceAcceleration.linearMotion.GetApproximateLength();

			
			localSpaceAcceleration.linearMotion.Multiply(current_direction, current_acceleration_length);

*/
			//
			// We need to change the target point to the extreme distance of the current direction, then we can
			// still seek as far as the thruster model is concerned. If we don't do this, then the missiles
			// will be affected by torque and have problems hitting the target.
			//
			Stuff::Point3D current_location;
			current_location = GetLocalToWorld();
			Stuff::Line3D target_line(current_location, direction_to_target, 1000.0f);
			target_line.FindEnd(&targetPoint);
			targetPosition = targetPoint;

//			localSpaceAcceleration.angularMotion.Zero();
//			worldSpaceVelocity.angularMotion.Zero(); // make sure we don't end up in a spin when we stop orienting.
//			worldSpaceAcceleration.angularMotion.Zero();
		}  
	}
ExitFunction:
;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
  Missile::LinearDragMotionSimulation(Stuff::Time till)
{
  //
  // Before doing the real math, see if we have any easy outs...
  //
  if (m_fTurnOffSeek || timeInAir >= burnTime)
		{
	  BaseClass::LinearDragMotionSimulation(till);
    return;
		}

  //
  // Has the last slice of time been greater than the time it would take to turn to that angle?
  // If so, just aim it at the target;

	Point3D local_direction;
  Point3D local_to_world_position;
  local_to_world_position = GetLocalToWorld();
	local_direction.Subtract(
		targetPosition,
		local_to_world_position
	);

	UnitVector3D new_direction;
  Stuff::Scalar new_direction_length = local_direction.GetLengthSquared();
  if (Small_Enough(new_direction_length))
		{
	  BaseClass::LinearDragMotionSimulation(till);
    return;
		}

  //
  // Normalize
  //
  new_direction_length = 1.0f / Sqrt(new_direction_length);
	new_direction.x = local_direction.x * new_direction_length;
	new_direction.y = local_direction.y * new_direction_length;
	new_direction.z = local_direction.z * new_direction_length;

  Stuff::Scalar differenceTargetAngleToPreviousVelocity;

  UnitVector3D previousDirection;
  Stuff::Scalar previousDirection_length = worldSpaceVelocity.linearMotion.GetLengthSquared();
  if (Small_Enough(previousDirection_length))
		{
	  BaseClass::LinearDragMotionSimulation(till);
    return;
		}

  //
  // Normalize
  //
  previousDirection_length = 1.0f / Sqrt(previousDirection_length);
	previousDirection.x = worldSpaceVelocity.linearMotion.x * previousDirection_length;
	previousDirection.y = worldSpaceVelocity.linearMotion.y * previousDirection_length;
	previousDirection.z = worldSpaceVelocity.linearMotion.z * previousDirection_length;

  
  differenceTargetAngleToPreviousVelocity = new_direction * previousDirection;


  // If we are aimed close enough the target, and we are physically close enough, then just assume we are at the target

  lastWorldSpaceVelocity = worldSpaceVelocity;
  BaseClass::LinearDragMotionSimulation(till);

  UnitVector3D currentDirection;
  Stuff::Scalar currentDirection_length = worldSpaceVelocity.linearMotion.GetLengthSquared();
  if (Small_Enough(currentDirection_length))
    return;

  //
  // Normalize
  //
  currentDirection_length = 1.0f / Sqrt(currentDirection_length);
	currentDirection.x = worldSpaceVelocity.linearMotion.x * currentDirection_length;
	currentDirection.y = worldSpaceVelocity.linearMotion.y * currentDirection_length;
	currentDirection.z = worldSpaceVelocity.linearMotion.z * currentDirection_length;
  
  Stuff::Scalar differencePreviousVelocityToCurrentVelocity;
  differencePreviousVelocityToCurrentVelocity = previousDirection * currentDirection;

  
  if (differencePreviousVelocityToCurrentVelocity < differenceTargetAngleToPreviousVelocity)
  {

		//
		// If this is true then the missile is oversteering. What this translates to is that the missile
		// turned more than was necessary last frame to end up pointing at the target. This is easy to do
		// on slower frame rates since the momentum carries them past their target during the long break between
		// frames. In order to compensate for this we use the following logic:
		//	if (missile turned passed target last frame)
		//	   point missile at the target
		//		 kill the angular motion and acceleration, so it stays pointing at it for the next frame.
		// 
		//
		// Some variables already defined at this point:
		//	new_direction - this is the normalized world space direction to the target prior to 
		//									simulating the linear drag/propulsion calculations
		//  currentDirection - this is the direction the missile is moving in after the simulation
		
		// cheating since the missiles parent should be the world, we aren't multiplying by it's parent
		local_to_world_position = GetLocalToWorld();
		local_direction.Subtract(
			targetPosition,
			local_to_world_position
		);
		LinearMatrix4D aligned_matrix = entityElement->GetNewLocalToParent();
		aligned_matrix.AlignLocalAxisToWorldVector(local_direction, Z_Axis, X_Axis, Y_Axis);
		SetNewLocalToParent(aligned_matrix);


    Stuff::Scalar linearMotionSpeed = localSpaceVelocity.linearMotion.GetApproximateLength();
    localSpaceVelocity.angularMotion.Zero();
    localSpaceVelocity.linearMotion.z = linearMotionSpeed;
    localSpaceVelocity.linearMotion.y = 0.0f;
    localSpaceVelocity.linearMotion.x = 0.0f;
		// reuse for acceleration
    linearMotionSpeed = localSpaceAcceleration.linearMotion.GetApproximateLength();
    localSpaceAcceleration.linearMotion.z = linearMotionSpeed;
    localSpaceAcceleration.linearMotion.y = 0.0f;
    localSpaceAcceleration.linearMotion.x = 0.0f;



















		//
		// new_direction is in world space
		//


/*		Stuff::Point3D p1, p2;
		p1 = new_direction;
		p2.MultiplyByInverse(p1, entityElement->GetNewLocalToParent());
//		Stuff::Point3D p2;
//		p2 = currentDirection;
//		Stuff::Point3D p3;
//		p3.Subtract(p1, p2);
//		LinearMatrix4D d;
//		d.BuildRotation(p3);
//		d.BuildTranslation(Point3D::Identity);
		Stuff::LinearMatrix4D new_local_to_parent;

//		new_local_to_parent.Multiply(entityElement->GetNewLocalToParent(), d);
//		p1 = entityElement->GetNewLocalToParent();
//		new_local_to_parent.BuildTranslation(p1);
//		new_local_to_parent.Normalize();

		new_local_to_parent.BuildRotation(p2);
		p1 = entityElement->GetNewLocalToParent();
		new_local_to_parent.BuildTranslation(p1);
		SetNewLocalToParent(new_local_to_parent);
//		new_local_to_parent.BuildTranslation(new_translation);


/*
		localSpaceAcceleration.angularMotion.Zero();
		worldSpaceAcceleration.angularMotion.Zero();
		localSpaceAcceleration.linearMotion.x = 0.0f;
		localSpaceAcceleration.linearMotion.y = 0.0f;
*/
		//
		// In order to preserve it's current acceleration, but make sure it hits the target we need to 
		// find the normalized direction that we want to go (
		//
/*
		Stuff::Scalar current_acceleration_length = worldSpaceAcceleration.linearMotion.GetApproximateLength();
		worldSpaceAcceleration.linearMotion.Multiply(new_direction, current_acceleration_length);

		current_acceleration_length = localSpaceAcceleration.linearMotion.GetApproximateLength();

		
		localSpaceAcceleration.linearMotion.Multiply(new_direction, current_acceleration_length);
	*/
  }  
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
  Missile::ProximityCheck(Stuff::Time till)
{
  const GameModel *model = GetGameModel();
  Point3D targetDistance;
  Point3D local_to_parent_position;

  Entity *target_entity = targetEntity.GetCurrent();


  Point3D targetLocalToOurParent;
  if (!GetParentEntity())
    return;																																	
	//
	// To avoid missiles chasing dead things we need to make sure we cut the gas when this is detected
	//
	// make sure we burn a little at least (.5)

  if (target_entity && target_entity->IsDestroyed() && timeInAir < burnTime/* && timeInAir > 0.5f*/)
   {
		m_nMissCount++; // this makes sure we run for at least a couple of frames to orient the missile correctly

	
	// This should no longer be needed since we'll just turn off seeking
 //   timeInAir = model->burnTime;
   }

	if(timeInAir >= burnTime)
	{
    return;
  }

	//
	// Don't do 
	//

  if (!target_entity || (target_entity->IsDerivedFrom(Map::DefaultData)) || m_fTurnOffSeek)
	{
		return;
	}

  
	LinearMatrix4D world_to_entity = LinearMatrix4D::Identity;
	world_to_entity.Invert(target_entity->GetLocalToWorld());
	ElementRenderer::Element *element = target_entity->GetElement();
	Check_Object(element);
	LinearMatrix4D world_to_new_world = LinearMatrix4D::Identity;
	world_to_new_world.Multiply(world_to_entity, element->GetNewLocalToParent());
  LinearMatrix4D targetPositionMatrix = LinearMatrix4D::Identity;
  // world_to_entity being reused as a temp.
  targetPositionMatrix.BuildTranslation(targetPosition);
  world_to_entity.Multiply(targetPositionMatrix, world_to_new_world);
  targetPosition = world_to_entity;




  targetLocalToOurParent.MultiplyByInverse(targetPosition, GetParentEntity()->GetLocalToWorld());



  local_to_parent_position = GetLocalToParent();
	targetDistance.Subtract(
		targetLocalToOurParent,
		local_to_parent_position
	);



  Stuff::Scalar distanceSquared = targetDistance.GetLengthSquared();
  if ((m_nDoubleTeleportPreventor < 5) && target_entity && (target_entity->IsDerivedFrom(MWObject::DefaultData)) &&
      (distanceSquared < model->proximityFuseDistance))
  {
    /*

  // Since it's going to die, we don't need to know about the orientation
    //
    // Can I call the CollisionHandler directly from here?
		Entity::CollisionData collision_data;

    UnitVector3D normal;
    local_to_world_position.Negate(targetDistance); // reusing local_to_world_position as temp
    normal.Normalize(local_to_world_position);
		collision_data.m_normal = normal;
    collision_data.m_otherEntity = target_entity;
		collision_data.m_otherVolume = NULL;
		collision_data.m_volume = NULL;
		collision_data.m_material = collision_query.m_material;
		collision_data.m_timeSlice =
			(line.m_length * t) * collider->GetTimeSlice(till);
		line.FindEnd(&collision_data.m_worldIntersectionPoint);
		DynamicArrayOf<Entity::CollisionData> *array = new DynamicArrayOf<Entity::CollisionData>(1);
		(*array)[0] = collision_data;

  

    PostCollision();
    SentenceToDeathRow();

    */

    //
    // If due to a data error (collision volume that doesn't have geometry in center) or some other mishap, we need to prevent
    // the missile from continually teleporting.
    //
    //
    m_nDoubleTeleportPreventor++;

    LinearMatrix4D targetDirectionLocalToWorld = LinearMatrix4D::Identity;

		//
		// Try going just a little bit through the point we are trying to hit to maximize collision chances
		//
    targetDirectionLocalToWorld.BuildTranslation(targetLocalToOurParent);
    targetDirectionLocalToWorld.AlignLocalAxisToWorldVector(targetDistance, Z_Axis, Y_Axis, X_Axis);
    SetNewLocalToParent(targetDirectionLocalToWorld);
		//
		// We have to immediately sync, or we have problems with splash damage location.
		// ** Seeing if I can do this as part of the damage handler instead
		// SyncMatrices(true);
  }
  else if (m_nDoubleTeleportPreventor >= 5)
  {
    //
    // Let it get out of range before it tries to teleport again.
    //
    if (distanceSquared > (model->proximityFuseDistance + 1.0f))
      m_nDoubleTeleportPreventor = 0;
		m_nMissCount++;

  }


}
/*
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
  Missile::ProximityCheck(Stuff::Time till)
{
  const GameModel *model = GetGameModel();
  Point3D targetDistance;
  Point3D local_to_parent_position;

  Point3D targetLocalToOurParent;
  if (!GetParentEntity())
    return;
  targetLocalToOurParent.MultiplyByInverse(targetPosition, GetParentEntity()->GetLocalToWorld());




  local_to_parent_position = GetLocalToParent();
	targetDistance.Subtract(
		targetLocalToOurParent,
		local_to_parent_position
	);



  Entity *target_entity = targetEntity.GetCurrent();
  Stuff::Scalar distanceSquared = targetDistance.GetLengthSquared();
  if (target_entity && (target_entity->IsDerivedFrom(MWObject::DefaultData)) &&
      (distanceSquared < model->proximityFuseDistance))
  {

    LinearMatrix4D targetDirectionLocalToWorld = LinearMatrix4D::Identity;
    targetDirectionLocalToWorld.BuildTranslation(targetLocalToOurParent);

  // Since it's going to die, we don't need to know about the orientation
    //
    // Can I call the CollisionHandler directly from here?
		Entity::CollisionData collision_data;

    UnitVector3D normal;



    Stuff::Scalar new_direction_length_inverse_sqrt = targetDistance.GetLengthSquared();
    Stuff::Scalar new_direction_length = Sqrt(new_direction_length_inverse_sqrt);
    if (Small_Enough(new_direction_length))
    {
      normal = UnitVector3D::Identity;
      //
      // Keep our current direction in this case
      //
      targetDirectionLocalToWorld.BuildRotation(worldSpaceVelocity.linearMotion);
    }
    else
    {
      //
      // Normalize
      //
      new_direction_length_inverse_sqrt = 1.0f / Sqrt(new_direction_length);
	    normal.x = -targetDistance.x * new_direction_length_inverse_sqrt;
	    normal.y = -targetDistance.y * new_direction_length_inverse_sqrt;
	    normal.z = -targetDistance.z * new_direction_length_inverse_sqrt;
      //
      // If we have a true line, align our direction to it
      //
      targetDirectionLocalToWorld.AlignLocalAxisToWorldVector(targetDistance, Z_Axis, Y_Axis, X_Axis);
    }
    //
    // We now have our position, and possibly our rotation so commit it.
    //
    SetNewLocalToParent(targetDirectionLocalToWorld);

		collision_data.m_normal = normal;
    if (target_collision_volume && !target_collision_volume->IsDestroyed())
    {
		  collision_data.m_otherVolume = target_collision_volume;
		  collision_data.m_material = target_collision_volume->m_material;
    }
    else
    {
		  collision_data.m_otherVolume = NULL;
      collision_data.m_material = MechWarrior4::MaterialCount;
    }
    collision_data.m_otherEntity = target_entity;
		collision_data.m_volume = NULL;

    collision_data.m_timeSlice = GetTimeSlice(till);

    collision_data.m_worldIntersectionPoint = targetPosition;

    DynamicArrayOf<Entity::CollisionData> *array = new DynamicArrayOf<Entity::CollisionData>(1);
		(*array)[0] = collision_data;

  

    PostCollision(array);
    SentenceToDeathRow();



  }


}
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Missile::CollisionHandler(
		Stuff::LinearMatrix4D *new_position,
		Stuff::DynamicArrayOf<CollisionData> *collisions
	)
{
	Check_Object(this);
	Check_Object(collisions);
	Verify(collisions->GetLength() == 1);
	Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));

	return BaseClass::CollisionHandler(new_position, collisions);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::SeekingThrusterSimulation(Stuff::Time till)
{
	Check_Object(this);
	const GameModel *model = GetGameModel();
	Check_Object(model);

	#if defined(MISSILE_BUG)
		SPEW((MISSILE_BUG, "Position: %f %f %f", 
			GetLocalToWorld()(3,0), GetLocalToWorld()(3,1), GetLocalToWorld()(3,2)));

		SPEW((MISSILE_BUG, "LocalSpaceVelocityLinearMotion: %f %f %f", 
			localSpaceVelocity.linearMotion.x, localSpaceVelocity.linearMotion.y, 
			localSpaceVelocity.linearMotion.z));

		SPEW((MISSILE_BUG, "LocalSpaceVelocityAngularMotion: %f %f %f", 
			localSpaceVelocity.angularMotion.x, localSpaceVelocity.angularMotion.y, 
			localSpaceVelocity.angularMotion.z));
	#endif

	#if defined(MISSILE_BUG)
		SPEW((MISSILE_BUG, "TargetPosition: %f %f %f", 
			targetPosition.x, targetPosition.y, targetPosition.z));
	#endif

	#if defined(TARGET_BUG)
		SPEW((TARGET_BUG, "TargetPosition: %f %f %f", 
			targetPosition.x, targetPosition.y, targetPosition.z));
	#endif

	if(timeInAir <= burnTime)
	{
		UnitVector3D new_direction;
		//
		//-----------------------------
		//Find direction in local space
		//-----------------------------
		//
		Stuff::Point3D local_direction;
		Stuff::Point3D temp_target_location;
		temp_target_location = targetPosition;
	//	Stuff::Scalar timeSlice =  GetTimeParameter(till);

//		local_direction.MultiplyByInverse(
//			temp_target_location,
//			GetLocalToWorld()
//		);
		//new_direction = UnitVector3D::Identity;
	//	local_direction.y = 0; 
	//  Stuff::Scalar new_direction_length = local_direction.GetLengthSquared();
		//
		// Gravity isn't supposedly acting on these objects but they seem to draw up short.
		//
	//	Stuff::Scalar gravity_compensation_factor = new_direction_length;
	//	Max_Clamp(gravity_compensation_factor, 2.0f);	
	//	temp_target_location.y += (g_Gravity * timeSlice * timeSlice) * gravity_compensation_factor;

		//
		// Re-get the direction since we are shifting the target position
		//
		local_direction.MultiplyByInverse(
			temp_target_location,
			GetLocalToWorld()
		);

		#if defined(MISSILE_BUG)
			SPEW((MISSILE_BUG, "TargetPositionInLocalSpace: %f %f %f", 
				local_direction.x, local_direction.y, local_direction.z));
		#endif

		Stuff::Scalar new_direction_length = local_direction.GetLengthSquared();
		Vector3D local_steer_direction;
		
//		if (!m_fTurnOffSeek)
//		{
			if (Small_Enough(new_direction_length))
			{
				new_direction = Vector3D::Forward;
			}
			else
			{
				//
				// Normalize
				//
				new_direction_length = 1.0f / Sqrt(new_direction_length);
				new_direction.x = local_direction.x * new_direction_length;
				new_direction.y = local_direction.y * new_direction_length;
				new_direction.z = local_direction.z * new_direction_length;
			}
			//
			//-------------------------------------------
			//Find the direction that we want to steer to
			//-------------------------------------------
			//
			local_steer_direction.Cross(
				Vector3D::Forward,
				new_direction
			);
			
			//
			//----------------------------------
			//We need to find the degree to turn
			//----------------------------------
			//
			Scalar degree_to_turn;
			Scalar sine = 0.0f;
			
			if (!Small_Enough(local_steer_direction))
			{
				sine = local_steer_direction.GetLength();
			}
				
			if(Small_Enough(sine))
			{
				degree_to_turn = 0.0f;
				local_steer_direction = Vector3D::Identity;
			}
			else
			{
				if(local_steer_direction.y < 0.0f)
				{
					sine = -sine;
				}
				degree_to_turn = 
					Arctan(sine, new_direction.z);

				#if defined(MISSILE_BUG)
					SPEW((MISSILE_BUG, "RadianToTurn: %f", degree_to_turn));
				#endif

					//
					// We need to clamp the turn, but it has to be clamped based on the time slice, it can't just be clamped a fixed amount per frame
					// or the slower frame rates won't be able to turn well.
					//

				Stuff::Scalar timeSlice =  GetTimeParameter(till);
				Scalar max_angle = model->maxTurnAngle * timeSlice ;

				Clamp(degree_to_turn, -max_angle, max_angle);
				#if defined(MISSILE_BUG)
					SPEW((MISSILE_BUG, "ClampedRadianToTurn: %f", degree_to_turn));
				#endif
				degree_to_turn /= sine;
				local_steer_direction *= degree_to_turn;
			}

			#if defined(MISSILE_BUG)
				SPEW((MISSILE_BUG, "AxisOfRotation: %f %f %f", 
					local_steer_direction.x, local_steer_direction.y, local_steer_direction.z));
			#endif

			//
			//-------------------------------------------
			//Negate the z value of the turn direction to 
			//-------------------------------------------
			//
			LinearMatrix4D force_to_parent = LinearMatrix4D::Identity;
			force_to_parent.BuildRotation(local_steer_direction);
			UnitVector3D force_forward;
			force_to_parent.GetLocalForwardInWorld(&force_forward);

			force_forward.x = -force_forward.x;
			force_forward.y = -force_forward.y;


	//		force_forward.z = -force_forward.z;
			local_steer_direction.Multiply(
				force_forward,
				model->thrusterAcceleration
			);

			#if defined(MISSILE_BUG)
				SPEW((MISSILE_BUG, "LocalForce: %f %f %f\n", 
					local_steer_direction.x, local_steer_direction.y, local_steer_direction.z));
			#endif

			ApplyLocalAcceleration(
				local_steer_direction,
				Vector3D::Backward
			);

			//
			// If Dot Product of the angles between current direction and the direction to target
			// are small enough, then kill the angular motion. It's a cheat to prevent over
			// correction.
			//
    
			Stuff::Scalar differenceTargetAngleToActualAngle;
   		
			local_direction.MultiplyByInverse(
					temp_target_location,
					GetLocalToWorld());

			new_direction_length = local_direction.GetLengthSquared();
			if (Small_Enough(new_direction_length))
				return;

			//
			// Normalize
			//
			new_direction_length = 1.0f / Sqrt(new_direction_length);
			new_direction.x = local_direction.x * new_direction_length;
			new_direction.y = local_direction.y * new_direction_length;
			new_direction.z = local_direction.z * new_direction_length;

    
			differenceTargetAngleToActualAngle = new_direction * UnitVector3D::Forward;
			if ( differenceTargetAngleToActualAngle >= 0.985f)
			{ 
				
				localSpaceVelocity.angularMotion.Zero();
				localSpaceAcceleration.angularMotion.Zero();
				Stuff::Scalar speed = localSpaceVelocity.linearMotion.GetApproximateLength();
				localSpaceVelocity.linearMotion.Multiply(new_direction, speed);

	/*
				LinearMatrix4D targetDirectionLocalToWorld;
				targetDirectionLocalToWorld.BuildRotation(new_direction);
				LinearMatrix4D localToParent;
				LinearMatrix4D oldLocalToWorld;
				oldLocalToWorld = parentEntity->GetLocalToWorld();
				localToParent.Multiply(targetDirectionLocalToWorld, oldLocalToWorld.Invert());
				SetNewLocalToParent(localToParent);
	*/    
			}
//		}
/*		else
		{
			Stuff::UnitVector3D current_direction;
			GetLocalToWorld().GetLocalForwardInWorld(&current_direction); 

/*
			Stuff::Scalar new_direction_length = current_direction.GetLengthSquared();
			if (Small_Enough(new_direction_length))
				return;

			//
			// Normalize
			//
			new_direction_length = 1.0f / Sqrt(new_direction_length);
			new_direction.x = current_direction.x * new_direction_length;
			new_direction.y = current_direction.y * new_direction_length;
			new_direction.z = current_direction.z * new_direction_length;
// * /
			current_direction.x = -current_direction.x;
			current_direction.y = -current_direction.y;

			local_steer_direction.Multiply(
				current_direction,
				model->thrusterAcceleration
			);

			localSpaceAcceleration.linearMotion += local_steer_direction;

	ApplyLocalAcceleration(
				local_steer_direction,
				Vector3D::Backward
			);
//			Stuff::Scalar speed = localSpaceVelocity.linearMotion.GetApproximateLength();
//			localSpaceVelocity.linearMotion.Multiply(new_direction, speed);

		}
*/    
	}
	else
	{
		//
		//------------------
		//We are out of fuel
		//------------------
		//
		#if defined(MISSILE_BUG)
			SPEW((MISSILE_BUG, "We are out of fuel"));
		#endif

		localSpaceDrag = Motion3D::Identity;

		UnitVector3D local_down;
		GetLocalToWorld().GetWorldDownInLocal(&local_down);
		localSpaceAcceleration.linearMotion.Multiply(
			local_down,
			g_Gravity
		);

		if(trailEffect.GetCurrent())
			trailEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);

		#if defined(MISSILE_BUG)

			UnitVector3D local_forward,local_up;
			GetLocalToWorld().GetLocalForwardInWorld(&local_forward);
			GetLocalToWorld().GetLocalUpInWorld(&local_up);

			SPEW((MISSILE_BUG, "Local Down: %f %f %f", local_down.x, local_down.y, local_down.z));
		
			SPEW((MISSILE_BUG, "Local Forward in Local: %f %f %f", local_forward.x,
				local_forward.y, local_forward.z));
			SPEW((MISSILE_BUG, "Local Up in Local: %f %f %f", local_up.x,
				local_up.y, local_up.z));
			SPEW((MISSILE_BUG, "WorldSpaceVelocityLinearMotion: %f %f %f\n", 
				worldSpaceVelocity.linearMotion.x, worldSpaceVelocity.linearMotion.y, 
				worldSpaceVelocity.linearMotion.z));
		#endif
	}
} 

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::PostCollisionExecute(Stuff::Time till)
{
	Check_Object(this);
	Verify(Close_Enough(GetLocalToParent(), GetLocalToWorld()));
	POSTCOLLISION_LOGIC("Missile");

	lastParameterization = till;
	initialLocalToParent = GetLocalToParent();
	initialWorldSpaceVelocity = worldSpaceVelocity,
	initialWorldSpaceAcceleration = worldSpaceAcceleration;

	if(doesAMSDestroyThisFrame)
	{
		CreateEffect(amsExplosionResource);
		SentenceToDeathRow();
	}

	BaseClass::PostCollisionExecute(till);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::LRMSeekerModel(Stuff::Time till)
{
	Check_Object(this);

	if (m_fTurnOffSeek)
	{
    localSpaceVelocity.angularMotion.Zero();
		localSpaceAcceleration.angularMotion.Zero();
		return; // leave the current direction alone since we're done turning
	}

	//
	// Don't continually circle, but just burn off fuel in the current direction instead.
	//
	if (m_nMissCount > 1)
	{
		m_fTurnOffSeek = true;
    localSpaceVelocity.angularMotion.Zero();
		localSpaceAcceleration.angularMotion.Zero();
		return;
	}

	
	Point3D local_to_world;
	local_to_world = GetLocalToWorld();

	CalculateTargetPosition(&targetPosition, till);
	targetPoint = targetPosition;
	//
	// Decide whether or not to make this missile arc in it's path.
	//
	Stuff::Scalar diffY = (targetPosition.y - local_to_world.y);

	if (diffY <= 50.0f)
	{
		Vector3D local_direction;
		local_direction.Subtract(
			targetPosition,
			local_to_world
		);
		
		Scalar true_distance = local_direction.GetApproximateLength();
		local_direction.y = 0;
		Scalar arc_value;
		arc_value = local_direction.GetLength();

		//
		//------------------------------------------------------------
		//Right here we need to tell the target how far we are from it
		//------------------------------------------------------------
		//
		if((true_distance < 50.0f) && (DoesAMSDestroy()))
		{
			ConveyDistanceToTarget(true_distance);
		}

		
		arc_value -= 200.0f;
		if(m_fAllowArcMissile && arc_value > 0.0f)
		{
			arc_value /= 2.0f; //reduced the angle since our curve code might get in the way.
			Max_Clamp(arc_value, 150.0f);
			targetPosition.y += ((1.0f / (timeInAir + 0.5f)) * arc_value);
//			targetPosition.y += arc_value;
		}		
		
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Missile::MRMSeekerModel(Stuff::Time till)
{
	Check_Object(this);

	if (m_fTurnOffSeek)
	{
    localSpaceVelocity.angularMotion.Zero();
		localSpaceAcceleration.angularMotion.Zero();
		return; // leave the current direction alone since we're done turning
	}

	Point3D local_to_world;
	local_to_world = GetLocalToWorld();

	CalculateTargetPosition(&targetPosition, till);

	if((targetPosition.y - local_to_world.y) <= 50.0)
	{
		Vector3D local_direction;
		local_direction.Subtract(
			targetPosition,
			local_to_world
		);
		
		Scalar true_distance = local_direction.GetApproximateLength();
/*
		local_direction.y = 0;
		Scalar arc_value;
		arc_value = local_direction.GetLength();
		arc_value -= 140.0f;
*/
		//
		//------------------------------------------------------------
		//Right here we need to tell the target how far we are from it
		//------------------------------------------------------------
		//
		if((true_distance < 50.0f) && (DoesAMSDestroy()))
		{
			ConveyDistanceToTarget(true_distance);
		}

/*
		if(arc_value > 0.0f)
		{
			arc_value /= 3;
			Max_Clamp(arc_value, 120.0f);
			targetPosition.y += arc_value;
		}		
*/
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::LongTomSeekerModel()
{
	Check_Object(this);

	Point3D local_to_world;
	local_to_world = GetLocalToWorld();

	if((targetPosition.y - local_to_world.y) <= 50.0)
	{
		Vector3D local_direction;
		local_direction.Subtract(
			targetPosition,
			local_to_world
		);
		
		local_direction.y = 0;
		Scalar arc_value;
		arc_value = local_direction.GetLength();
		arc_value -= 140.0f;
		if(arc_value > 0.0f)
		{
			arc_value /= 3;
			Max_Clamp(arc_value, 120.0f);
			targetPosition.y += arc_value;
		}		
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::SSRMSeekerModel(Stuff::Time till)
{
	Check_Object(this);

	if (m_fTurnOffSeek)
	{
    localSpaceVelocity.angularMotion.Zero();
		localSpaceAcceleration.angularMotion.Zero();
		return; // leave the current direction alone since we're done turning
	}

	Point3D local_to_world;
	local_to_world = GetLocalToWorld();

	CalculateTargetPosition(&targetPosition, till);

	Point3D origin;
	origin = GetLocalToWorld();
	Vector3D local_direction;
	local_direction.Subtract(
		targetPosition,
		origin
	);

	Scalar true_distance = local_direction.GetApproximateLength();
	//
	//------------------------------------------------------------
	//Right here we need to tell the target how far we are from it
	//------------------------------------------------------------
	//
	if((true_distance < 50.0f) && (DoesAMSDestroy()))
	{
		ConveyDistanceToTarget(true_distance);
	}

#if 0
	if(local_direction.GetLength() > 80.0f)
	{
		//
		//--------------------------------------------
		//Now we want to cast a ray towards the ground
		//--------------------------------------------
		//
		Vector3D ray_direction;
		ray_direction.Multiply(srmPitchVector, GetLocalToWorld());

		Stuff::Line3D line;
		line.length = 20.0f;
		line.direction = ray_direction;
		line.origin = origin;

		//
		// Prepare query
		//	
		Stuff::Normal3D normal;
		CollisionQuery query(&line, &normal, CanBeShotFlag, this);

		//
		// Cast ray
		//
		Check_Object(CollisionGrid::Instance);
		Entity *entity_hit = CollisionGrid::Instance->ProjectLine(&query);
		if(entity_hit)
		{
			if(entity_hit != Map::GetInstance())
			{
				SPEW(("daberger", "I did not hit the map, and I hit %s", (const char *)entity_hit->instanceName));
				srmYTargetOffset += (20 - line.length);
				SPEW(("daberger", "We are adding to the offset %f", srmYTargetOffset));
			}
			else
			{
				SPEW(("daberger", "I hit the fucking Map"));
				srmYTargetOffset = (20 - line.length);
			}
		}
		else
		{
			srmYTargetOffset = 0.0f;
			SPEW(("daberger", "We have cleared the offset"));
		}

		targetPoint.y += srmYTargetOffset;
		SPEW(("daberger", "The Y target is %f\n", targetPoint.y));
	}
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::SRMSeekerModel(Stuff::Time till)
{
	Check_Object(this);

	if (m_fTurnOffSeek)
	{
    localSpaceVelocity.angularMotion.Zero();
		localSpaceAcceleration.angularMotion.Zero();
		return; // leave the current direction alone since we're done turning
	}
/*
	if(timeInAir <= burnTime)
	{
		Mover::StraightLineMotionSimulation(till);	
	}
	else
	{
		localSpaceDrag = Motion3D::Identity;

		UnitVector3D local_down;
		GetLocalToWorld().GetWorldDownInLocal(&local_down);
		localSpaceAcceleration.linearMotion.Multiply(
			local_down,
			g_Gravity
		);

    LinearDragMotionSimulation(till);

		if(trailEffect.GetCurrent())
			trailEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
	}
*/
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::ConveyDistanceToTarget(Stuff::Scalar distance)
{
	Check_Object(this);

	if(targetMWObject.GetCurrent() == NULL)
		return;

	Point3D local_to_world;
	local_to_world = GetLocalToWorld();
	amsExplosionResource = targetMWObject.GetCurrent()->ReactToMissileApproach(distance, local_to_world);
	if(amsExplosionResource != ResourceID::Null)
		doesAMSDestroyThisFrame = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Missile::CreateEffect(const Adept::ResourceID& effect_id)
{

	if (effect_id == ResourceID::Null)
		return;

	Resource resource(effect_id);
	Verify(resource.DoesResourceExist());
	
	ClassID class_ID;
	class_ID = Entity::GetClassIDFromDataListID(effect_id);
	Verify(class_ID != NullClassID);
	
	LinearMatrix4D effect_location = GetLocalToWorld();

	Effect::CreateMessage effect_create_message(
		sizeof(Effect::CreateMessage),
		DefaultEventPriority,
		Entity::CreateMessage::DefaultFlags,
		class_ID,
		Effect::DefaultFlags,
		effect_id,
		effect_location,
		0.0f,
		Entity::ExecutionStateEngine::AlwaysExecuteState,
		NameTable::NullObjectID,
		Entity::DefaultAlignment
	);
	MemoryStream stream(&effect_create_message, effect_create_message.messageLength);

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

	entity->SyncMatrices(true);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Point3D&
	Missile::CalculateTargetPosition(Stuff::Point3D *new_position, Time till)
{
	Check_Object(this);
	Check_Pointer(new_position);

	//
	//-------------------------------------------------------------------
	// If we are targeted on something that isn't the map, figure out its
	// current position
	//-------------------------------------------------------------------
	//
	Entity *target_entity = targetEntity.GetCurrent();
	MWObject * target_mwobject = targetMWObject.GetCurrent();
	if((target_entity) && (!target_entity->IsDerivedFrom(Map::DefaultData)))
	{
		if (target_entity->IsDestroyed())
		{
			target_collision_volume = NULL;
			target_entity = GetFirstAcceptableParentEntity(target_entity);
			if (target_entity)
			{
				Check_Object(target_entity);
				targetEntity.Remove();
				targetEntity.Add(target_entity);
			}
			//
			// If we don't have anything valid to aim at, then just find a spot on the ground below the object we were
			// previously aiming at
			//
			else
			{
				targetEntity.Remove();
				//
				// Cast a ray down from the last known position.
				//
				Vector3D ray_direction = Vector3D::Down;
				Stuff::Line3D line;
				line.m_length = 1000.0f;
				line.m_direction = ray_direction;
				line.m_origin = *new_position;
				line.m_origin.y += 5.0f;
				//
				// Prepare query
				//	
				Stuff::Normal3D normal;
				CollisionQuery query(&line, &normal, CanBeShotFlag, this);
				CollisionGrid::Instance->ProjectLine(&query);
				line.FindEnd(new_position);
			}
		}
		if (target_entity && !target_entity->IsDestroyed())
		{

			//
			// Rather than indirectly getting the collision volume, I'll just get where the original raycast hit
			// relative to the entity that we are tracking.
			//

			Stuff::Point3D target_local_to_world;
			(*new_position).Multiply(targetOffsetFromEntity, target_entity->GetLocalToWorld());
	
			//
			//------------------------------------------------------------------
			// If it is an MWObject, look for the center torso damage object and
			// seek its collision volume
			//------------------------------------------------------------------
			//
			//
			// Make sure our current target_collision_volume is valid first...
			//
//			if (!target_collision_volume || target_collision_volume->IsDestroyed())
//			{
//				GetTargetCollisionVolume();
//			}

			//
			// Aim at the targetOffset in this case.
			//
//			if (target_collision_volume) // we didn't find one previously
//			{
//				*new_position = target_collision_volume->m_worldSpaceBounds.localToParent;
//			}
//			else
//			{
//				*new_position = target_entity->GetLocalToWorld();
//			}
//
			if (target_mwobject )
			{
				Check_Object(target_mwobject);

				//
				//---------------------------------------------------------------
				// If this is a vehicle, we use dead reckoning to figure out
				// the best point along its potential path for us to hit it,
				// given our two relative speeds
				//---------------------------------------------------------------
				//
				if (target_mwobject->IsDerivedFrom(Vehicle::DefaultData))
				{
//					Stuff::Point3D hit_point_offset;
					Stuff::LinearMatrix4D  mw_object_ltw;
					Stuff::LinearMatrix4D  mw_object_ltw_inverse;
					Stuff::LinearMatrix4D  target_ltp_mwobject;
					mw_object_ltw = target_mwobject->GetLocalToWorld();
					mw_object_ltw_inverse.Invert(mw_object_ltw);
					target_ltp_mwobject.Multiply(target_entity->GetLocalToWorld(), mw_object_ltw_inverse);
					//
					// If we use a fixed offset like this is it true when we rotate in the prediction?
					// Probably since we are only guessing at linear motion...

//					hit_point_offset.MultiplyByInverse(*new_position,(Stuff::Point3D)mw_object_ltw);

					Stuff::Scalar my_velocity(worldSpaceVelocity.linearMotion.GetApproximateLength());

					Vehicle* v = Cast_Object(Vehicle*,target_mwobject);
					Check_Object(v);
      
					Stuff::Point3D distanceToTarget;
					distanceToTarget.Subtract((Stuff::Point3D)v->GetLocalToWorld(), (Stuff::Point3D)GetLocalToWorld());
					if (!Small_Enough(distanceToTarget.GetLengthSquared()))
					{
						Stuff::Scalar time = TimeToCollide(v->GetLocalToWorld(),
															 v->currentSpeedMPS,
															 (Stuff::Point3D)GetLocalToWorld(),
															 my_velocity);

		        Stuff::Scalar timeSlice = GetTimeParameter(till);
						if (time < 0)
						{
							time = 0.0f;	// negative time is bad; it means we will never hit -- so we clamp it at 0 minimum
						}
						else if (time > 2)
						{
							time = 2.0f;	// no point predicting more than, say, 2 seconds in advance
						}
						
						time += timeSlice; // compensate for the last frame.

						v->EstimateFuturePosition(new_position,time);

	//
	// Right now the missiles won't alter their target based on any animation information. Jerry needs to work with me
	// to find a cheap method for finding out this info. We may not have a cheaper way than storing the index and querying 
	// the array every frame
	//					
	/*					ElementRenderer::Element *element = target_mwobject->animationArray[vehiclerootJointIndex]->GetElement();
						Check_Object(element);
						//
						// Multiply by the root's localtoparent
						//
						camera_local_to_torso.Multiply(tempJumpMatrix, element->GetLocalToParent());
	*/
						mw_object_ltw.BuildTranslation(*new_position);
						mw_object_ltw_inverse.Multiply(target_ltp_mwobject, mw_object_ltw);
						(*new_position).Multiply(targetOffsetFromEntity, mw_object_ltw_inverse);

					}	// we were able to do a prediction (!smallenough)
				}	// it's a vehicle
			}	// if target_mwobject has anything in it
			//
			//----------------------------------------------------------
			// The object is something else, so just seek it where it is
			//----------------------------------------------------------
			//
//			else
//			{
//				*new_position = target_entity->GetLocalToWorld();
//			}
		} // is the entity we currently have !destroyed
	}	// if we have an enitity and it's not the map

	//
	//---------------------------------------------------
	// If we hit the map, just fly to where we where told
	//---------------------------------------------------
	//
	else
	{
		*new_position = targetPoint;
	}
	#if defined(MISSILE_BUG)
		SPEW((MISSILE_BUG, "EstimatedTargetPosition: %f %f %f", 
			new_position->x, new_position->y, new_position->z));
	#endif
	return *new_position;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Entity*
	Missile::TraceToParent(Entity *entity)
{
 	if(!entity)
		return NULL;

	if(entity->IsDerivedFrom(MWMover::DefaultData))
	{
		MWMover *mover;
		mover = Cast_Object(MWMover *, entity);
		if(mover->myParentVehicle)
			return mover->myParentVehicle;
	}
	return entity;
}
