#include "MW4Headers.hpp"

#include "HighExplosiveWeapon.hpp"
#include "Explosive.hpp"
#include "MWObject.hpp"
#include "SubsystemClassData.hpp"
#include "MWApplication.hpp"

#include <Adept\Map.hpp>
#include <Adept\Site.hpp>
#include <Adept\DamageObject.hpp>

#include <MLR\MLRTexturePool.hpp>

//#############################################################################
//###############################    HighExplosiveWeapon    ###################
//#############################################################################

HighExplosiveWeapon::ClassData*
	HighExplosiveWeapon::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	HighExplosiveWeapon::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			HighExplosiveWeaponClassID,
			"MechWarrior4::HighExplosiveWeapon",
			ProjectileWeapon::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);
}

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HighExplosiveWeapon::HighExplosiveWeapon(
	ClassData *class_data,
	CreateMessage *message,
	ReplicatorID *base_id,
	ElementRenderer::Element *element
):
	ProjectileWeapon(class_data, message, base_id, element)
{
	Check_Pointer(this);
	Check_Object(message);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HighExplosiveWeapon::~HighExplosiveWeapon()
{
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	HighExplosiveWeapon::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;
		LinearMatrix4D site_local_to_world;

		//
		//-------------------------
		//Initialize the velocities
		//-------------------------
		//
		Check_Object(sitePointer);
		site_local_to_world = sitePointer->GetLocalToWorld();

		Vector3D direction;
		Point3D target_point;
		targetQuery.m_line->FindEnd(&target_point);
		direction.Subtract(target_point,(Stuff::Point3D)site_local_to_world);

		LinearMatrix4D direction_matrix = LinearMatrix4D::Identity;
		direction_matrix.BuildTranslation((Stuff::Point3D)site_local_to_world);
		direction_matrix.AlignLocalAxisToWorldVector(direction, Z_Axis, Y_Axis, X_Axis);

		initial_velocity.linearMotion.Multiply(
			model->initialLinearVelocity,
			direction_matrix
		);
		
		initial_acceleration.linearMotion = model->initialLinearAcceleration;

		ReplicatorID target_id;
		target_id = ReplicatorID::Null;
		
		Entity *ray_source = targetQueryEntity.GetCurrent();
		if(ray_source)
		{
			Check_Object(ray_source);
			target_id = ray_source->GetReplicatorID();
		}

		//
		//--------------------------------
		//Create the Missile CreateMessage
		//--------------------------------
		//

		Explosive::CreateMessage projectile_create_message(
			sizeof(Explosive::CreateMessage),
			DefaultEventPriority,
			CreateMessage::DefaultFlags,
			class_ID,
			Explosive::DefaultFlags,
			model->projectileModelResource,
			sitePointer->GetLocalToWorld(),
			0.0f,
			Explosive::ExecutionStateEngine::StraightLineMotionState,
			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);

		DamageObject *center_torso = GetParentVehicle()->damageObjects.Find(DamageObject::CenterTorsoArmorZone);
		if(center_torso)
		{
			Entity *torso_entity = center_torso->parentEntity;
			Check_Object(torso_entity);
			ReplicatorID id = GetParentVehicle()->GetReplicatorID();
			//This is a hack...grab our center torsos
			//First blow the shit out of ourselves!
			Normal3D normal(0.0f, 1.0f, 0.0f);
			Point3D damage_location;
			damage_location = GetLocalToWorld();
// MSL 5.06 Armor Mode
			MWApplication *m_App;
			m_App = MWApplication::GetInstance ();
			m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;

			Adept::Entity__TakeDamageMessage message(
				id,
				id,
				200,
				m_ArmorMode,
				HighExplosiveDamageType,
				normal,
				damage_location,
				model->heatToDeal,
				false,
				model->itemID
			);

			torso_entity->Receive(&message);
		}
	}
}

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

