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

#pragma once

#include "MW4.hpp"
#include "Vehicle.hpp"

#pragma warning (push)
#include <vector>
#pragma warning (pop)

namespace Adept
{
	class Effect;
}

namespace MechWarrior4
{
	class Airplane;
	class Subsystem;

	extern DWORD Executed_Airplane_Count;

	//##########################################################################
	//###############    Airplane::ExecutionStateEngine    #####################
	//##########################################################################

	class Airplane__ExecutionStateEngine:
		public Vehicle__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Vehicle__ExecutionStateEngine BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef Airplane__ExecutionStateEngine*
			(*Factory)(
				Airplane *entity,
				FactoryRequest *request
			);

		static Airplane__ExecutionStateEngine*
			Make(
				Airplane *mover,
				FactoryRequest *request
			);

	protected:
		Airplane__ExecutionStateEngine(
			ClassData *class_data,
			Airplane *mover,
			FactoryRequest *request
		);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			TakingOffMotionState = Vehicle::ExecutionStateEngine::StateCount,
			LandingMotionState,
			CrashingDeathState,
			TaxiState,
			PopupState,
			PopdownState,
			FloatState,
			StateCount
		};

	int
		RequestState(
			int new_state,
			void* data = NULL
		);

	protected:
		static const StateEntry
			StateEntries[];

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

	//##########################################################################
	//#####################    Airplane::ModelResource   #######################
	//##########################################################################

	class Airplane__GameModel:
		public Vehicle__GameModel
	{
	public:
		
		Stuff::Scalar
			flyingAltitude;

		Stuff::Radian
			tiltSpeed;

		Stuff::Radian
			tiltDegree;

		Stuff::Scalar
			percentageOfTurnToStartTilt;
		
		Stuff::Scalar
			percentageOfSpeedToStartTilt;

		Stuff::Radian
			pitchSpeed;

		Stuff::Radian
			pitchDegree;
		
		Stuff::Scalar
			percentageOfSpeedToStartPitch;

		Stuff::Scalar maxClimb,maxDescent;

		Stuff::Scalar
			maxTurnAngle,
			thrusterAcceleration,
			takeOffSpeed;

		Adept::ResourceID
			takeOffResource,
			takeOffGroundResource,
			landingResource,
			landingGroundResource;

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

		static void
			ConstructGameModel(Script *script);

		enum {
			FlyingAltitudeAttributeID = Vehicle__GameModel::NextAttributeID,
			TiltSpeedAttributeID,
			TiltDegreeAttributeID,
			PercentageOfTurnToStartTiltAttributeID,
			PercentageOfSpeedToStartTiltAttributeID,
			MaxTurnAngleAttributeID,
			ThrusterAccelerationAttributeID,
			PitchSpeedAttributeID,
			PitchDegreeAttributeID,
			PercentageOfSpeedToStartPitchAttributeID,
			TakeOffSpeedAttributeID,
			MaxClimbAttributeID,
			MaxDescentAttributeID,
			TakeOffResourceAttributeID,
			TakeOffGroundResourceAttributeID,
			LandingResourceAttributeID,
			LandingGroundResourceAttributeID,
			NextAttributeID
		};
	};

	//##########################################################################
	//##################    Mech::CreateMessage    #############################
	//##########################################################################

	class Airplane__CreateMessage:
		public Vehicle__CreateMessage
	{
	public:

		Stuff::Scalar
			altitude;

		Airplane__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,
			const char *entity_name,
			const ResourceID& armature_id,
			const Adept::ResourceID& site_id,
			const ResourceID& subsystem_id,
			const ResourceID& damage_id,
			char skin_prefix,
			int team_prefix,
			int pilot_prefix,
			int name_index,
			bool has_instance_name,
			Stuff::Scalar plane_altitude
		):
			Vehicle__CreateMessage(
				length,
				priority,
				message_flags,
				class_id,
				replicator_flags,
				instance_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment,
				initial_velocity,
				initial_acceleration,
				entity_name,
				armature_id,
				site_id,
				subsystem_id,
				damage_id,
				skin_prefix,
				team_prefix,
				pilot_prefix,
				name_index,
				has_instance_name
			),
			altitude(plane_altitude)
			{};

		static void
			ConstructCreateMessage(Script *script);
	};
	
	//##########################################################################
	//############################    Airplane   ###############################
	//##########################################################################

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Vehicle__ClassData							Airplane__ClassData;
	typedef Vehicle__Message							Airplane__Message;
	
	//-----------------------  End of inheritance stuff ------------------------

	class Airplane:
		public Vehicle
	{
		friend class MovementClass;

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Vehicle BaseClass;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef Airplane__ClassData					ClassData;
		typedef Airplane__GameModel					GameModel;
		typedef Airplane__Message					Message;
		typedef Airplane__ExecutionStateEngine		ExecutionStateEngine;
		typedef Airplane__CreateMessage				CreateMessage;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static Airplane*
			Make(
				CreateMessage *message,
				ReplicatorID *base_id
			);
		Adept::Replicator::CreateMessage*
			SaveMakeMessage(MemoryStream *stream, Adept::ResourceFile *res_file);

		void
			SaveInstanceText(Stuff::Page *instance_page);
		void
			Respawn(Adept::Entity::CreateMessage *message);
		void
			CommonCreation(CreateMessage *message);
		void
			LoadAnimationScripts();

	protected:
		Airplane(
			ClassData *class_data,
			CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);
		
		~Airplane();

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

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

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	protected:
		static stlport::vector<Scalar> *m_Heights;
		bool m_OnGround;

	public:
		void AdjustAltitude (void);
		bool OnGround (void)
		{ return m_OnGround; }
	
		void
			PreCollisionExecute(Stuff::Time till);
		void
			PostCollisionExecute(Stuff::Time till);
		virtual void
			TakeOff(Stuff::Scalar runway_distance);
		void
			Land(void);

		void
			Popup(Stuff::Scalar to_height);
		void
			Popdown(Stuff::Scalar to_height);
		void
			Float(const Stuff::Point3D& dest);

		Stuff::Point3D
			takeOffTargetPosition;
		Stuff::Point3D
			takeOffIntermidiatePosition;
		Stuff::Point3D
			takeOffFinalOffset;
		bool
			shouldBeDone;
		bool
			shouldDie;
		bool
			shouldLeaveReckage;

		Stuff::Scalar flyingAltitude;
		Stuff::Scalar m_AttackAltitude;
		bool m_Attacking;

		Stuff::Point3D&
			EstimateFuturePosition(
				Stuff::Point3D *new_position,
				Stuff::Scalar seconds,
				bool consider_terrain = true
			);

		Stuff::SlotOf<Adept::Effect *>
			m_crashingEffect;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		enum {
			TakingOffSFXAttributeID = Vehicle::NextAttributeID,
			InAirSFXAttributeID,
			IdleSFXAttributeID,
			NextAttributeID
		};

	public:
		
		int
			takingOffSFX,
			inAirSFX,
			idleSFX,
			dyingSFX;

		bool
			hasTakeOffAnimationLoaded;

		void SetTakingOff()
			{Check_Pointer(this); takingOffSFX = 1; inAirSFX = 0; idleSFX = 0; dyingSFX = 0;}
		void SetInAir()
			{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 1; idleSFX = 0; dyingSFX = 0;}
		void SetIdle()
			{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 0; idleSFX = 1; dyingSFX = 0;}
		void SetDying()
			{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 0; idleSFX = 0; dyingSFX = 1;}
		void SetDead()
			{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 0; idleSFX = 0; dyingSFX = 0;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tilt Stuff
	//

		Stuff::Scalar tiltAngle;
		Stuff::Scalar tiltRequest;
		Stuff::Scalar pitchAngle;
		Stuff::Scalar pitchRequest;

		void TiltPlane(Stuff::Scalar time_slice);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//

	public:
		void TurnOn();
		void TurnOff();
		virtual void LandingMovementSimulation(Stuff::Time till);
		void FlyingMovementSimulation(Stuff::Time till);
		void TakeOffMovementSimulation(Stuff::Time till);
		void PopUpOrDownSimulation(Stuff::Scalar time_slice, Stuff::Scalar height);
		void FloatSimulation(Stuff::Scalar time_slice);
		void ComputeForwardSpeed(Stuff::Scalar time_slice);

		virtual void
			TakeOffThrusterSimulation(Stuff::Time till, const Stuff::Vector3D& new_velocity, const Stuff::Vector3D& instantanious_angular_velocity,bool canswitch);
		void
			CrashingDeathMovementSimulation(Stuff::Time till);
		void
			ReactToDestruction(int damage_mode, int damage_type);
		bool
			CollisionHandler(
				Stuff::LinearMatrix4D *new_position,
				Stuff::DynamicArrayOf<CollisionData> *collisions
			);

		void
			GetNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation);

	private:
		Stuff::Scalar m_PopupHeight;
		Stuff::Scalar m_PopdownHeight;
		Stuff::Scalar m_PopupClimbSpeed;

		Stuff::Point3D m_FloatTargetPosition;
		Stuff::Scalar m_FloatSpeed;
		Stuff::YawPitchRoll m_YPR;

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

	};

	inline Airplane__ExecutionStateEngine::Airplane__ExecutionStateEngine(
		ClassData *class_data,
		Airplane *mover,
		FactoryRequest *request
	):
		BaseClass(class_data, mover, request)
			{}
}
