//===========================================================================//
// File:	Missile.hpp														
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 05/27/99  DPB  Created File and Initial Functionality
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "MW4.hpp"

#include "WeaponMover.hpp"

namespace MechWarrior4
{	

	class Missile;
	class MWObject;

	//##########################################################################
	//###########################   Missile::GameModel    ######################
	//##########################################################################

	class Missile__GameModel:
		public WeaponMover__GameModel
	{
	public:
		
		Stuff::Scalar
			maxTurnAngle,
			maxLiveTime,
			thrusterAcceleration;
		Stuff::Scalar
		  proximityFuseDistance;

		enum {
			MaxTurnAngleAttributeID = WeaponMover__GameModel::NextAttributeID,
			ThrusterAccelerationAttributeID,
			MaxLiveTimeAttributeID,
			ProximityFuseDistanceAttributeID,
			NextAttributeID
		};

		static bool
			ReadAndVerify(
				Missile__GameModel *model,
				ModelAttributeEntry *attribute_entry, 
				const char *data,
				char **error,
				int error_buffer = 128
			);

		static void
			ConstructGameModel(Script *script);
	};

	//##########################################################################
	//##################    WeaponMover::CreateMessage    ######################
	//##########################################################################

	class Missile__CreateMessage:
		public WeaponMover__CreateMessage
	{
	public:
		Adept::ReplicatorID
			targetID;
		Stuff::Point3D
			targetPoint;
		Stuff::Scalar
			burnTime;

		Missile__CreateMessage(
			size_t length,
			int priority,
			int message_flags,
			Stuff::RegisteredClass::ClassID class_id,
			int replicator_flags,
			const ResourceID& instance_id,
			const Stuff::LinearMatrix4D &creation_matrix,
			Stuff::Scalar age,
			int execution_state,
			int name_id,
			int entity_alignment,
			const Stuff::Motion3D &initial_velocity,
			const Stuff::Motion3D &initial_acceleration,
			Stuff::Scalar damage_amount,
			Stuff::Scalar heat_amount,
			Stuff::Scalar max_distance,
// MSL 5.03 Min Distance
//			Stuff::Scalar min_distance,
			const Adept::ReplicatorID& inflicting_id,
			Stuff::Scalar splash_radius,
			Stuff::Scalar percentage_damage_direct_hit,
			Stuff::Scalar min_percentage_damage_sphere,
			Stuff::Scalar max_percentage_damage_sphere,
			int item_id,
			const Adept::ReplicatorID& target_id,
			const Stuff::Point3D& target_point,
			Stuff::Scalar burn_time
			
		):
			WeaponMover__CreateMessage(
				length, 
				priority, 
				message_flags, 
				class_id, 
				replicator_flags,
				instance_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment,
				initial_velocity,
				initial_acceleration,
				damage_amount,
				heat_amount,
				max_distance,
// MSL 5.03 Min Distance
//				min_distance,
				inflicting_id,
				splash_radius,
				percentage_damage_direct_hit,
				min_percentage_damage_sphere,
				max_percentage_damage_sphere,
				item_id
			),
				targetID(target_id),
				targetPoint(target_point),
				burnTime(burn_time)
				{}


	};

	//##########################################################################
	//###############    Missile::ExecutionStateEngine    ######################
	//##########################################################################

	class Missile__ExecutionStateEngine:
		public WeaponMover__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef WeaponMover__ExecutionStateEngine BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef Missile__ExecutionStateEngine*
			(*Factory)(
				Missile *weapon,
				FactoryRequest *request
			);

		static Missile__ExecutionStateEngine*
			Make(
				Missile *weapon,
				FactoryRequest *request
			);

	protected:
		Missile__ExecutionStateEngine(
			ClassData *class_data,
			Missile *weapon,
			FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			LRMMotionState = WeaponMover__ExecutionStateEngine::StateCount,
			SRMMotionState,
			MRMMotionState,
			SSRMMotionState,
			BombMotionState,
			LongTomMotionState,
			StateCount
		};

	protected:
		static const StateEntry
			StateEntries[];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      	TestInstance() const;
	};
	
	//##########################################################################
	//############################    Missile    ###############################
	//##########################################################################

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef WeaponMover__ClassData						Missile__ClassData;
	typedef WeaponMover__Message						Missile__Message;
	
	extern DWORD Executed_Missile_Count;

	//-----------------------  End of inheritance stuff ------------------------

	class Missile:
		public WeaponMover
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef WeaponMover BaseClass;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef Missile__ClassData						ClassData;
		typedef Missile__GameModel						GameModel;
		typedef Missile__Message						Message;
		typedef Missile__ExecutionStateEngine			ExecutionStateEngine;
		typedef Missile__CreateMessage					CreateMessage;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static Missile* 
			Make(
				CreateMessage *message,
				ReplicatorID *base_id
			);

		Missile(
			ClassData *class_data,
			CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);

		~Missile();

		void
			Reuse(
				const CreateMessage *message,
				ReplicatorID *base_id
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Flag Support
	//
	public:
		enum
		{
			DoesAMSDestroyBit = WeaponMover::NextFlagBit,
			NextFlagBit
		};

		enum 
		{
			DoesAMSDestroyFlag = 1<<DoesAMSDestroyBit
		};

		bool
			DoesAMSDestroy()
				{Check_Object(this); return (replicatorFlags&DoesAMSDestroyFlag) != 0;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Game Model support
	//
	public:
		const GameModel*
			GetGameModel()
				{return Cast_Pointer(const GameModel*, gameModelResource.GetPointer());}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
		void
			PreCollisionExecute(Stuff::Time till);
		bool
			CollisionHandler(
				Stuff::LinearMatrix4D *new_position,
				Stuff::DynamicArrayOf<CollisionData> *collisions
			);
		void
			PostCollisionExecute(Stuff::Time till);
		void
			LRMSeekerModel(Stuff::Time till);
		void
			MRMSeekerModel(Stuff::Time till);
		void
			SRMSeekerModel(Stuff::Time till);
		void
			SSRMSeekerModel(Stuff::Time till);
		void
			LongTomSeekerModel();
		void
			SeekingThrusterSimulation(Stuff::Time till);
		void
			UpdateNewLocalToParents(Stuff::Time till);
		void
			ConveyDistanceToTarget(Stuff::Scalar distance);
		void
			CreateEffect(const Adept::ResourceID& effect_id);

		void
			LinearDragMotionSimulation(Stuff::Time till);
		void
			ProximityCheck(Stuff::Time till);
		void 
			GetTargetCollisionVolume();
		Entity*
			GetFirstAcceptableParentEntity(Entity* entity);

		Entity*
			Missile::TraceToParent(Entity *entity);
		

		Stuff::SlotOf<Adept::Entity*>
			targetEntity;
		Stuff::SlotOf<MWObject *>
			targetMWObject;
    
		CollisionVolume *
		  target_collision_volume;

		Stuff::Point3D
			targetPoint;
		Stuff::Point3D
			targetOffsetFromEntity;

		Stuff::Point3D
			targetPosition;
		Stuff::Scalar
			timeInAir;
		Stuff::Scalar
			burnTime;

		bool 
			m_fAllowArcMissile; // used to allow us to not arc for objects like helicoptors

		bool 
			m_fTurnOffSeek; // so that we don't keep seeking a destroyed object, or we don't keep circling

		Stuff::Motion3D
		  lastWorldSpaceVelocity;
		int 
		  m_nDoubleTeleportPreventor; // this is used to prevent us from continually teleporting to the same spot.
		int 
			m_nMissCount; // used to prevent constantly circling missiles


		Stuff::UnitVector3D
			srmPitchVector;
		Stuff::Scalar
			srmYTargetOffset;

	private:
		Stuff::Point3D&
			CalculateTargetPosition(Stuff::Point3D *new_position, Stuff::Time till);

		bool doesAMSDestroyThisFrame;
		Adept::ResourceID amsExplosionResource;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      		TestInstance() const;
	};

	inline
		Missile__ExecutionStateEngine::Missile__ExecutionStateEngine(
			ClassData *class_data,
			Missile *mover,
			FactoryRequest *request
		):
			WeaponMover__ExecutionStateEngine(class_data, mover, request)
	{
	}
}
