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

#pragma once

#include "MW4.hpp"
#pragma warning (push)
#include <stlport\string>
#pragma warning (pop)

#include "MWObject.hpp"
#include "Engine.hpp"
#include "SensorCellMap.hpp"


namespace Adept
{
	class ShadowLight;
}

namespace Adept
{
	class DamageObject;
	class Effect;
}

namespace MechWarrior4
{	

	class Vehicle;
	class Torso;
	class Engine;
	class VehicleInterface;
	class MWInternalDamageObject;
	class Weapon;
	class MoverAI;
	class CombatAI;

	void VehicleSecurityCheckStart();
	void VehicleSecurityCheckStop();


	class VehicleCommand :
		public Stuff::Plug
	{
	public:

		enum
		{
			JumpCommand = 0,
			PowerDownCommand,
			CrouchCommand,
			GetUpCommand,
			PressFlushCommand,
			ReleaseFlushCommand,
			SelfDestructCommand,
			SetTargetCommand,
			ToggleSearchLightCommand,
			Lancemate1Command,
			Lancemate2Command,
			Lancemate3Command,
			LancemateAllCommand,
			LancemateAttackMyTargetCommand,
			LancemateDefendMyTargetCommand,
			LancemateFormOnMeCommand,
			LancemateHoldFireCommand,
			LancemateGoToMyNavPointCommand,
			LancemateStopCommand,
			LancemateShutDownCommand,
			LancemateAttackNearestCommand,
			LancemateRepairCommand,
			StopJumpCommand,
			EjectCommand
		};


		int m_Command;

		VehicleCommand():Stuff::Plug(DefaultData)
		{
		}
	};

	//##########################################################################
	//#####################    Vehicle::ModelResource   ########################
	//##########################################################################

	class Vehicle__GameModel:
		public MWObject__GameModel
	{
	public:
		typedef MWObject__GameModel BaseClass;

		Stuff::Scalar
			modelmaxSlope,
			modelstartSlopeDeceleration,
			slopeDecel1,
			slopeDecel2,
			slopeDecel3;

		Stuff::Radian
			topSpeedTurnRate,
			fullStopTurnRate;					// Turn rate of vehicle

		Stuff::Scalar
			minSpeed,
			maxSpeed,
			minReverseSpeed,
			maxReverseSpeed,
			minMaxSpeed;		//Used for engine upgrading on the mech level

		// max speed when gimped
		Stuff::Scalar
			maxGimpSpeed;

		// if you request to stand you will imediatly
		// transition if you are less than this speed
		Stuff::Scalar
			minStandTransitionSpeed;

		Stuff::Scalar
			acceleration;

		Stuff::Scalar
			decceleration;

		Stuff::Scalar
			reverseAccelerationMultiplier;

		Stuff::Scalar
			reverseDeccelerationMultiplier;
		
		Stuff::Scalar
			targetLockTime;

		Adept::ResourceID
			trailEffectsTable,
			shadowStream;

		int
			m_attackType;

		Stuff::Scalar m_treadLength;

		enum {
			TopSpeedTurnRateAttributeID = MWObject__GameModel::NextAttributeID,
			FullStopTurnRateAttributeID,
			MaxReverseSpeedAttributeID,
			MinReverseSpeedAttributeID,
			MaxSpeedAttributeID,
			MinMaxSpeedAttributeID,
			MinSpeedAttributeID,
			AccelerationAttributeID,
			DeccelerationAttributeID,
			ReverseAccelerationMultiplierAttributeID,
			ReverseDeccelerationMultiplierAttributeID,
			TargetLockTimeAttributeID,
			MaxGimpSpeedAttributeID,
			MinStandTransitionSpeedAttributeID,
			MaxSlopeAttributeID,
			StartSlopeDecelerationAttributeID,
			SlopeDecel1AttributeID,
			SlopeDecel2AttributeID,
			SlopeDecel3AttributeID,
			AttackTypeAttributeID,
			TreadLengthAttributeID,
			NextAttributeID
		};

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

		static void
			ConstructGameModel(Script *script);
		
	};

	//##########################################################################
	//###############    Vehicle::ExecutionStateEngine    ######################
	//##########################################################################

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

		typedef MWObject::ExecutionStateEngine BaseClass;

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

		static Vehicle__ExecutionStateEngine*
			Make(
				Vehicle *mover,
				FactoryRequest *request
			);

	protected:
		Vehicle__ExecutionStateEngine(
			ClassData *class_data,
			Vehicle *mover,
			FactoryRequest *request
		);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			FallingMotionState = MWMover::ExecutionStateEngine::StateCount,
			FlyingMotionState,
			AnimatedMotionState,
			DrivingMotionState,
			DestroyedState,
			AIMotionState,						// ai is controlling system
			DyingState,								// vehicle is sliding to a stop before blowing up
			DroppingState,							// vehicle is droping from a dropship
			StateCount
		};

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

	protected:
		static const StateEntry
			StateEntries[];

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


	//##########################################################################
	//############################    Vehicle    ###############################
	//##########################################################################

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef MWObject__Message			Vehicle__Message;
	typedef MWObject__UpdateMessage		Vehicle__UpdateMessage;
	typedef MWObject__CreateMessage		Vehicle__CreateMessage;
	typedef MWObject__ClassData			Vehicle__ClassData;

	extern DWORD Executed_Vehicle_Count;

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

	class Vehicle:
		public MWObject
	{
		friend class MovementClass;

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

		typedef MWObject BaseClass;
		friend class Vehicle__ExecutionStateEngine;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef Vehicle__ClassData							ClassData;
		typedef Vehicle__GameModel							GameModel;
		typedef Vehicle__Message							Message;
		typedef Vehicle__ExecutionStateEngine				ExecutionStateEngine;
		typedef Vehicle__CreateMessage						CreateMessage;
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static Vehicle*
			Make(
				CreateMessage *message,
				Adept::ReplicatorID *base_id
			);
		void
			SaveInstanceText(Stuff::Page *page);

	protected:
		Vehicle(
			ClassData *class_data,
			CreateMessage *message,
			Adept::ReplicatorID *base_id,
			ElementRenderer::Element *element
		);
		
		void
			Respawn(Adept::Entity::CreateMessage *message);
		void
			CommonCreation(CreateMessage *message);

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

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

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

		virtual Stuff::Scalar
			GetTurnSpeed()
			{
				Check_Object(this);
				const GameModel *model = GetGameModel();
#ifdef LAB_ONLY
				if (m_DebugFast)
				{
					return Lerp(model->fullStopTurnRate, model->topSpeedTurnRate, (currentSpeedMPS/10.0f)/model->maxSpeed);
				}
				else
#endif
				return Lerp(model->fullStopTurnRate, model->topSpeedTurnRate, currentSpeedMPS/model->maxSpeed);
			}

		virtual Stuff::Scalar GetMaxSpeed();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		enum {
			SpeedDemandMPSAttributeID = MWObject::NextAttributeID,
			CurrentSpeedMPSAttributeID,
			LocalGroundPitchAttributeID,
			LocalGroundRollAttributeID,
			RawLocalGroundPitchAttributeID,
			RawLocalGroundRollAttributeID,
			VehicleMovingSFXAttributeID,
			VehicleIdleSFXAttributeID,
			VehicleDyingSFXAttributeID,
			NextAttributeID
		};

	public:
		
		int
			vehicleMovingSFX,
			vehicleIdleSFX,
			vehicleDyingSFX;

		void SetMoving()
			{Check_Pointer(this); vehicleMovingSFX = 1; vehicleIdleSFX = 0; vehicleDyingSFX = 0;}
		void SetIdle()
			{Check_Pointer(this); vehicleMovingSFX = 0; vehicleIdleSFX = 1; vehicleDyingSFX = 0;}
		void SetDying ()
			{Check_Pointer(this); vehicleMovingSFX = 0; vehicleIdleSFX = 0; vehicleDyingSFX = 1;}
		void SetDead()
			{Check_Pointer(this); vehicleMovingSFX = 0; vehicleIdleSFX = 0; vehicleDyingSFX = 0;}

		int m_LastState;
		Stuff::Scalar
			speedDemand,
			yawDemand,
			pitchDemand,
			rollDemand,
			speedDemandMPS,
			currentSpeedMPS,
			currentSpeedKPH,
			speedDemandKPH;

		Stuff::Scalar
			maxSlope,
			startSlopeDeceleration;
#ifdef LAB_ONLY
		bool m_DebugFast;
#endif
		Stuff::Scalar m_WaterDelta;			// depth of unit in water

		Stuff::Scalar
			m_groundRaycastHeight; // height of solid collision volume so that we don't pop on buildings

		Stuff::Point3D dirRequest;				// for movement

		bool followDirRequest;			// true if track dirRequest point
		bool followDirRequestReverse;	// true if should track to reverse of dirRequest

		int m_DeathDamageMode;		// for dieing mode to pass on after skid to stop
		int m_DeathDamageType;

		Stuff::Scalar
			localGroundPitch,
			localGroundRoll,
			rawLocalGroundPitch,
			rawLocalGroundRoll;  // raw are plain numbers that are not locked to a degree
		Stuff::Scalar m_RawGroundPitch;			// true ground pitch
		Stuff::Vector3D m_LocalNormal,m_WorldAvgNormal;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// This is for inteface commands and network commands...
	//

		void ClearLancemate(void);
		virtual void ProcessCommand(int command);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Animation Support
	//
	public:
		virtual void AnimDiagTest1(void){animStateEngine->RequestState(AnimationStateEngine::Test1State);};
		virtual void AnimDiagTest2(void){animStateEngine->RequestState(AnimationStateEngine::Test2State);};
		virtual void AnimDiagTest3(void){animStateEngine->RequestState(AnimationStateEngine::Test3State);};
		virtual void AnimDiagTest4(void){animStateEngine->RequestState(AnimationStateEngine::Test4State);};
		virtual void AnimDiagTest5(void){animStateEngine->RequestState(AnimationStateEngine::Test5State);};
		virtual void AnimDiagTest6(void){animStateEngine->RequestState(AnimationStateEngine::Test6State);};
		virtual void AnimDiagTest7(void){animStateEngine->RequestState(AnimationStateEngine::Test7State);};
		virtual void AnimDiagTest8(void){animStateEngine->RequestState(AnimationStateEngine::Test8State);};

		void FindGroundAngle(void);
		void FindGroundAngleUnitDiamond(void);
		
		bool internalViewPoint;
		bool usingEyeSpring;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
		void ReactToDestruction(int damage_mode, int damage_type);
		virtual void TurnOn (void);
		virtual void TurnOff (void);
		virtual void GetTransSpeedKPH (Stuff::Scalar& forward,Stuff::Scalar& reverse)
		{ forward = 0;reverse = 0;}
		virtual void GetMaxSpeedKPH (Stuff::Scalar& forward,Stuff::Scalar& reverse)
		{ forward = 0;reverse = 0;}
		virtual void GetTransSpeedNormalized (Stuff::Scalar& forward,Stuff::Scalar& reverse)
		{ forward = 0;reverse = 0;}
		
		int
			GetExecutionSlot();

		void
			PreCollisionExecute(Stuff::Time till);
		#if defined(LAB_ONLY)
			void
				SyncMatrices(bool update_matrix);
		#endif
		void
			PostCollisionExecute(Stuff::Time till);

		bool
			CollisionHandler(
				Stuff::LinearMatrix4D *new_position,
				Stuff::DynamicArrayOf<CollisionData> *collisions
			);

		void RemoveFromExecution();

		int
			GetTableArray()
				{Check_Object(this); return Adept::NameTable::VehicleArray;}

		virtual void
			AddStatsToString(std::string& s);

		void CreateTrail();

		void SelfDestruct();
		virtual void ProcessSelfDestruct();
		virtual void Eject() { }

		int m_needSelfDestruct;

		SlotOf <Adept::Effect *> m_SecondaryExplosion;

		Adept::ResourceID
			currentTrailID;

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

		BYTE
			materialHit;

		virtual void ComputeForwardSpeed(Stuff::Scalar time_slice);

		void ComputeFrictionSpeed(Stuff::Scalar time_slice);
	
		bool
			vehicleRunsInterface;

		enum {
			FootNormal,
			FootLocked,
			FootReturn
		};

		int leftFootDown;
		int rightFootDown;

		static Stuff::Scalar
			Vehicle::GetHeightAtPoint(
				const Stuff::Point3D& point,
				Adept::Entity* from_who
			);

		
		int
			respawnCount;

		//These are mirrored in a defines file that is read in by vehicles who need this.
		//So when you add here you must match your changes in the attacktype.defines file
		enum{
			DefaultAttackType = 0,
			NightShadeAttackType,
			ShiloneAttackType
		};


		int
			teamNumber;

		void
			SetTeam(int team)
		{
			teamNumber = team;
		}

		int
			GetTeam()
		{
			return teamNumber;
		}

// MSL 5.06 Armor Mode
		int
			m_ArmorMode;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      		TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		void
			UpdateVehiclePosition(const Stuff::Scalar time_slice );
		void
			HookUpSubsystems(void);

		void
			BecomeInteresting(bool render_me);
		void
			BecomeUninteresting();

		Engine*
			GetEngine(void)
				{return engine;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Dead-reckoning functions
	//
	public:
		Stuff::Point3D&
			EstimateFuturePosition(
				Stuff::Point3D *new_position,
				Stuff::Scalar seconds,
				bool consider_terrain = true
			);

		
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Network Smoothing
	//
		bool
			correctingPosition,
			correctingRotation;

		Stuff::Point3D
			correctionPosition;

		Stuff::YawPitchRoll
			correctionAngle;

		Stuff::Scalar
			rotationCorrectionTime;

		Stuff::Scalar
			positionCorrectionTime;

		virtual void GetNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation);
		virtual void GetDeadReckonedNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation);
		virtual void ClearNetworkPosition();
		virtual void SetNetworkCorretionPosition(Stuff::Point3D new_position, Stuff::YawPitchRoll new_rotation, Point3D velocity, Scalar vel_request,  Scalar latency, Scalar update_rate);
		virtual bool GetNetworkAdjustment(Stuff::Scalar time_slice, Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation);
		
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Sensor cell map

	protected:
		int
			m_SensorCellMapX;

		int
			m_SensorCellMapZ;

		Stuff::Time
			m_LastSensorCellPositionUpdate;

		SensorCellMap*
			GetSensorCellMap();

		void
			AddToSensorCellMap();

		void
			RemoveFromSensorCellMap();

		void
			UpdateSensorCellMapPosition();
	

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Subsystem vars
	public:
		bool
			DoesHaveLightAmp()
				{Check_Object(this); return m_doesHaveLightAmp;}
	protected:
		Engine
			*engine;
		Adept::ShadowLight
			*shadow;
// MSL 5.02 Shadow
		Stuff::Scalar
			shadowIntensity;
		bool
			m_doesHaveLightAmp;
	};

	inline
		Vehicle__ExecutionStateEngine::Vehicle__ExecutionStateEngine(
			ClassData *class_data,
			Vehicle *vehicle,
			FactoryRequest *request
		):
			BaseClass(class_data, vehicle, request)
	{
	}
}
