//===========================================================================//
// File:	MWMover.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"
#include <Adept\Mover.hpp>

namespace Adept
{
	class Site;
	class InternalDamageObject;
}

namespace MechWarrior4
{
	class MWMover;
	class MWObject;
	class AI;

	//##########################################################################
	//###############    MWMover::ExecutionStateEngine    ##################
	//##########################################################################

	class MWMover__ExecutionStateEngine:
		public Adept::Mover__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Adept::Mover__ExecutionStateEngine BaseClass;

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

		static MWMover__ExecutionStateEngine*
			Make(
				MWMover *mover,
				FactoryRequest *request
			);

	protected:
		MWMover__ExecutionStateEngine(
			ClassData *class_data,
			MWMover *mover,
			FactoryRequest *request
		);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			RegularMotionState = Adept::Mover::ExecutionStateEngine::StateCount,
			CameraMotionState,
			StateCount
		};

	protected:
		static const StateEntry
			StateEntries[];

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

	//##########################################################################
	//##################    Mover::CreateMessage    #######################
	//##########################################################################

	class MWMover__CreateMessage:
		public Adept::Mover__CreateMessage
	{
	public:
		typedef Adept::Mover__CreateMessage BaseClass;

#if NSWIZZLE
		char jointName[128];

		Adept::ResourceID armatureStreamResourceID;
		Adept::ResourceID siteStreamResourceID;
#else
		Adept::ResourceID siteStreamResourceID;
		Adept::ResourceID armatureStreamResourceID;

		char jointName[128];
#endif

		MWMover__CreateMessage(
			size_t length,
			int priority,
			int message_flags,
			Stuff::RegisteredClass::ClassID class_id,
			int replicator_flags,
			const Adept::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 Adept::ResourceID& armature_id,
			const Adept::ResourceID& site_id
		):
			Adept::Mover__CreateMessage(
				length, 
				priority, 
				message_flags, 
				class_id, 
				replicator_flags,
				instance_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment,
				initial_velocity,
				initial_acceleration
			),
			armatureStreamResourceID(armature_id),
			siteStreamResourceID(site_id)
			{
				Check_Pointer(entity_name);
				Str_Copy(jointName, entity_name, sizeof(jointName));
			}

		static void
			ConstructCreateMessage(Script *script);
	};

	//##########################################################################
	//############################    MWMover    ###############################
	//##########################################################################

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Adept::Mover__ClassData		MWMover__ClassData;
	typedef Adept::Mover__Message		MWMover__Message;
	typedef Adept::Mover__GameModel		MWMover__GameModel;
	typedef Adept::Mover__UpdateMessage	MWMover__UpdateMessage;
	
	//-----------------------  End of inheritance stuff ------------------------

	class MWMover:
		public Adept::Mover
	{
		friend class MovementClass;

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

		typedef Adept::Mover BaseClass;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef MWMover__ClassData				ClassData;
		typedef MWMover__Message				Message;
		typedef MWMover__ExecutionStateEngine	ExecutionStateEngine;
		typedef MWMover__CreateMessage			CreateMessage;
		typedef MWMover__GameModel				GameModel;

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

		void
			SaveInstanceText(Stuff::Page *page);
		void
			Respawn(Adept::Entity::CreateMessage *message);
		void 
			Reuse(Adept::Entity::CreateMessage *message);
		void
			ReuseArmature();

	protected:
		void
			LoadArmatureFromResource(
				const Adept::ResourceID &armature_stream_id,
				Adept::ReplicatorID *base_id
			);
		void
			LoadSitesFromResource(const Adept::ResourceID &site_stream_id);

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

		~MWMover();

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

		void
			BecomeInteresting(bool render_me);
		virtual void
			CheckVideoStates(bool render_me);

		void
			NotifyAIShot(AI& ai, Adept::ReplicatorID inflicting_entity_id);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Child Support
	//
	public:
		void
			ConnectSitesToZone(Adept::InternalDamageObject *zone);
		void
			SetDamageObject(Adept::DamageObject *damage_object);

		Stuff::ChainOf<Adept::Entity *>*
			GetChildEntityChain()
		{Check_Object(this); return &childEntityChain;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:

		int 
			m_isDark;

			Stuff::AffineMatrix4D
				LTread;

			Stuff::AffineMatrix4D
				RTread;		
		void DetermineUV (Stuff::Time till);

		enum 
		{
			IsDarkAttributeID = Adept::Mover::NextAttributeID,
			LTreadAttributeID,
			RTreadAttributeID,
			NextAttributeID
		};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Renderer Support
	//
	public:
		char
			GetSkinPrefix()
				{Check_Object(this); return m_skinPrefix;}
		void
			SetSkinPrefix(char new_prefix)
				{Check_Object(this); m_skinPrefix = new_prefix;}

		int
			GetPilotDecal()
				{Check_Object(this); return m_pilotDecal;}
		void
			SetPilotDecal(int pilot)
				{Check_Object(this); m_pilotDecal = pilot;}

		int
			GetTeamDecal()
				{Check_Object(this); return m_teamDecal;}
		void
			SetTeamDecal(int team)
				{Check_Object(this); m_teamDecal = team;}

	protected:
		char
			m_skinPrefix;
		int
			m_pilotDecal,
			m_teamDecal;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
		void PreCollisionExecute(Stuff::Time till);

		MWObject
			*GetParentVehicle()
				{Check_Object(this); return myParentVehicle;}

		MWObject
			*myParentVehicle;

		Adept::ResourceID
			armatureStreamResourceID;
		Adept::ResourceID
			siteStreamResourceID;

		Stuff::SortedChainOf<Adept::Site*, Stuff::MString>
			m_sites;

		void
			ReactToDamageTaken(Stuff::Scalar damage_taken, const Adept::ReplicatorID& inflicting_entity, int weaponID, int damageType);

		bool
			FriendlyFire(const TakeDamageMessage *message);
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Damage/Destruction Support
	//
	public:
		void
			ReactToHit(const Adept::Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit);
		void
			ReactToDestruction(int damage_mode, int damage_type);
		void
			ReactToInternalDamage(int damage_mode);
		void
			CreatePartDestructionEffect(const Adept::ResourceID& resource_id);
		virtual void
			NotifyProjectileApproaching(const Stuff::Point3D& origin);
		void
			ToggleLightsOff(bool toggle);

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

	inline
		MWMover__ExecutionStateEngine::MWMover__ExecutionStateEngine(
			ClassData *class_data,
			MWMover *mover,
			FactoryRequest *request
		):
			Mover__ExecutionStateEngine(class_data, mover, request)
	{
	}

}
