//===========================================================================//
// File:	entity.hpp                                                           //
// Project: MUNGA           Brick: Entity Manager                            //
// Contents: Interface specification for entity class                        //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 11/29/94  JMA  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#if !defined(ENTITY_HPP)
#	define ENTITY_HPP

#	if !defined(SIMULATE_HPP)
#		include <simulate.hpp>
#	endif

#	if !defined(ORIGIN_HPP)
#		include <origin.hpp>
#	endif

#	if !defined(LINMTRX_HPP)
#		include <linmtrx.hpp>
#	endif

	class Player;
	class NotationFile;
	class DamageZone;
	class Damage;
	class Subsystem;

#	define ENTITY_CONTINUATION
#	include <entity2.hpp>

	//##########################################################################
	//###########################    Entity    #################################
	//##########################################################################

	class Entity:
		public Simulation
	{
		friend class Entity__StaticVideoSocketIterator;
		friend class Entity__DynamicVideoSocketIterator;
		friend class Entity__AudioSocketIterator;
		friend class Entity__GaugeSocketIterator;
		friend class Entity__AudioLocationIterator;

	//##########################################################################
	// Shared Data support
	//
	public:
		typedef Entity__SharedData SharedData;
		SharedData*
			GetSharedData();

		static Derivation ClassDerivations;

		static SharedData DefaultData;

	//##########################################################################
	// Message Support
	//
	public:
		enum {
			MakeMessageID = Simulation::NextMessageID,
			MakeReadyMessageID,
			RemakeEntityMessageID,
			RemakeReadyMessageID,
			RemakeCompleteMessageID,
			RemakeIncompleteMessageID,
			DestroyEntityMessageID,
			TransferEntityMessageID,
			TransferCompleteMessageID,
			TransferIncompleteMessageID,
			BecomeInterestingMessageID,
			BecomeUninterestingMessageID,
			UpdateMessageID,
			SubscribeReplicantMessageID,
			UnsubscribeReplicantMessageID,
			TakeDamageMessageID,
			TakeDamageStreamMessageID,
			PlayerLinkMessageID,
			NextMessageID
		};

		typedef Entity__Message								Message;
		typedef Entity__MakeMessage						MakeMessage;
		typedef Entity__MakeReadyMessage					MakeReadyMessage;
		typedef Entity__RemakeEntityMessage				RemakeEntityMessage;
		typedef Entity__RemakeReadyMessage				RemakeReadyMessage;
		typedef Entity__RemakeCompleteMessage			RemakeCompleteMessage;
		typedef Entity__RemakeIncompleteMessage		RemakeIncompleteMessage;
		typedef Entity__DestroyEntityMessage			DestroyEntityMessage;
		typedef Entity__TransferEntityMessage			TransferEntityMessage;
		typedef Entity__TransferCompleteMessage		TransferCompleteMessage;
		typedef Entity__TransferIncompleteMessage		TransferIncompleteMessage;
		typedef Entity__BecomeInterestingMessage		BecomeInterestingMessage;
		typedef Entity__BecomeUninterestingMessage	BecomeUninterestingMessage;
		typedef Entity__UpdateMessage						UpdateMessage;
		typedef Entity__SubscribeReplicantMessage		SubscribeReplicantMessage;
		typedef Entity__UnsubscribeReplicantMessage	UnsubscribeReplicantMessage;
		typedef Entity__TakeDamageMessage				TakeDamageMessage;
		typedef Entity__TakeDamageStreamMessage		TakeDamageStreamMessage;
		typedef Entity__PlayerLinkMessage				PlayerLinkMessage;
		typedef Entity__DynamicMessage					DynamicMessage;
      typedef Entity__MakeMapMessage					MakeMapMessage;


		void
			Receive(Event *event);

		void
			LocalDispatch(Message *what)
				{Receiver::Receive(Cast_Object(Receiver::Message*,what));}

		void
			Dispatch(Receiver::Message *what);

		void
			DispatchToReplicant(
				Message *what,
				HostID host
			);

		void
			DispatchToReplicants(Message *what);

	private:
		static const HandlerEntry MessageHandlerEntries[];

	protected:
		static MessageHandlerSet MessageHandlers;

	//##########################################################################
	// Attribute Support
	//
	public:
		enum {
			LocalToWorldAttributeID = Simulation::NextAttributeID,
			LocalOriginAttributeID,
			DamageZoneCountAttributeID,
			DamageZonesAttributeID,
			NextAttributeID
		};

	private:
		static const IndexEntry AttributePointers[];

	protected:
		static AttributeIndexSet	AttributeIndex;

	//
	// public attribute declarations go here
	//
	public:
		LinearMatrix	localToWorld;
		Origin			localOrigin;
		int				damageZoneCount;
		DamageZone		**damageZones;


		int
			GetDamageZoneIndex(const CString &damage_zone_name) const;


	//
	// virtual access
	//
	public:
		virtual Vector3D
			GetWorldLinearVelocity()
         	{return Vector3D(0.0f, 0.0f, 0.0f);}
		virtual Vector3D
      	GetWorldLinearAcceleration()
         	{return Vector3D(0.0f, 0.0f, 0.0f);}

	//##########################################################################
	// Model Support
	//
	public:
		UpdateMessage*
			Execute(const Time &till);

		Subsystem*
			GetSubsystem(int index)
				{
					Check(this); Verify((unsigned)index < subsystemCount);
					return subsystemArray[index];
				}
		Simulation*
			GetSimulation(int index);
		int
			GetSubsystemCount()
				{Check(this); return subsystemCount;}
		Subsystem*
			FindSubsystem(const char* name);

		typedef void
			(Entity::*Performance)(Scalar time_slice);

		typedef Entity__UpdateRecord UpdateRecord;

		void
			SetPerformance(Performance performance)
				{
					Check(this);
					activePerformance = (Simulation::Performance)performance;
				}

		enum {
			EntitySubsystemID = -1
		};

		static int
			FindSubsytemID(
				const char *model_name,
				const char *subsystem_name
         );
	public:

		enum {
				DamageZoneUpdateModelBit = Simulation::NextUpdateModelBit,
				NextUpdateModelBit
			};

		enum {
				DamageZoneUpdateModelFlag = 1 << DamageZoneUpdateModelBit
		};

		Logical
			DamageZoneUpdateModelFlagSet()
		{Check(this); return (updateModel & DamageZoneUpdateModelFlag); }

	protected:

		void
			WriteUpdateRecord(
				Simulation::UpdateRecord *message,
				int update_model
			);
		void
			UpdateMessageHandler(UpdateMessage *message);

		void
			ReadUpdateRecord(Simulation::UpdateRecord *message);

		void
			ReadDamageUpdateRecord(Simulation::UpdateRecord *update_record);

		void
			WriteDamageUpdateRecord(Simulation::UpdateRecord *update_record);

		void
			PerformAndWatch(
				const Time &till,
				MemoryStream *update_stream
			);

		int
			subsystemCount;
		Subsystem
			**subsystemArray;
		Origin
			updateOrigin;

		void
			TakeDamageStreamMessageHandler(TakeDamageStreamMessage *message);
		void
			TakeDamageMessageHandler(TakeDamageMessage *message);
		void
			PlayerLinkMessageHandler(PlayerLinkMessage *message);

	//##########################################################################
	// Renderer Support
	//
	public:
		void
			AddStaticVideoComponent(Component *component);
		void
			AddDynamicVideoComponent(Component *component);
		void
			AddAudioComponent(Component *component);

		typedef Entity__StaticVideoSocketIterator
			StaticVideoSocketIterator;
		typedef Entity__DynamicVideoSocketIterator
			DynamicVideoSocketIterator;
		typedef Entity__AudioSocketIterator
			AudioSocketIterator;

		virtual Enumeration
			GetAudioRepresentation(Entity *linked_entity);

	private:
		SChainOf<Component*>
			staticVideoSocket;
		SChainOf<Component*>
			dynamicVideoSocket;
		SChainOf<Component*>
			audioSocket;

	//##########################################################################
	// Flag Support
	//
	public:
		//
		// MasterInstance - created on owning host, replicated on remote hosts,
		//		sends updates to replicants
		// ReplicantInstance - created on remote hosts, receives updates from
		// 	MasterInstance
		// IndependantInstance - created on owning host, replicated on remote
		//		hosts, never receives updates from MasterInstance
		// HermitInstance - created on owning host, is not replicated, does
		//		send updates
		//
		enum {
			InstanceBits = Simulation::NextBit,
			ValidBit = InstanceBits+2,
			TransferableBit,
			InterestBit,
			InterestLockedBit,
			DynamicBit,
			TrappedBit,
			StatueBit,
			MapBit,
			PreRunBit,
			CondemnedBit,
			NextBit
		};
		enum Instance
		{
			MasterInstance=0,
			ReplicantInstance=1<<InstanceBits,
			IndependantInstance=2<<InstanceBits,
			HermitInstance=3<<InstanceBits
		};
		enum {
			InstanceMask			= HermitInstance,
			ValidFlag				= 1<<ValidBit,
			TransferableFlag		= 1<<TransferableBit,
			InterestFlag			= 1<<InterestBit,
			InterestLockedFlag	= 1<<InterestLockedBit,
			DynamicFlag				= 1<<DynamicBit,
			TrappedFlag				= 1<<TrappedBit,
			StatueFlag				= 1<<StatueBit,
			MapFlag					= 1<<MapBit,
			PreRunFlag				= 1<<PreRunBit,
			CondemnedFlag			= 1<<CondemnedBit,
			TypeMask					= DynamicFlag|TrappedFlag|MapFlag,
//			DefaultFlags			= MasterInstance
			DefaultFlags			= DynamicFlag|MasterInstance
		};
		enum Type {
			StaticType		= 0,
			DynamicType		= DynamicFlag,
			TrappedType		= DynamicFlag|TrappedFlag,
			StatueType		= DynamicFlag|TrappedFlag|StatueFlag,
			MapType			= DynamicFlag|MapFlag,
			TrappedMapType	= DynamicFlag|TrappedFlag|MapFlag,
		};

	//##########################################################################
	// Instance Type support
	//
	public:
		void
			SetInstance(Instance type)
				{Check(this); simulationFlags &= ~InstanceMask; simulationFlags |= type;}
		Instance
			GetInstance()
				{Check(this); return (Instance)(simulationFlags&InstanceMask);}

		static LWord
			EntityFlagsSetInstance(LWord entity_flags, Instance type)
				{
					entity_flags &= ~InstanceMask;
					entity_flags |= type;
					return entity_flags;
				}
		static Instance
			EntityFlagsGetInstance(LWord entity_flags)
				{return (Instance)(entity_flags&InstanceMask);}

	//##########################################################################
	// Validity Support
	//
	public:
		void
			SetValidFlag()
				{Check(this); simulationFlags |= ValidFlag;}
		void
			SetInvalidFlag()
				{Check(this); simulationFlags &= ~ValidFlag;}
		Logical
			IsValid()
				{Check(this); return (simulationFlags&ValidFlag) != 0;}

		void
			SetPreRunFlag()
				{Check(this); simulationFlags |= PreRunFlag;}
		void
			SetNoPreRunFlag()
				{Check(this); simulationFlags &= ~PreRunFlag;}
		Logical
			IsPreRunnable()
				{Check(this); return (simulationFlags&PreRunFlag) != 0;}

		void
			SetCondemnedFlag()
				{Check(this); simulationFlags |= CondemnedFlag;}
		Logical
			IsCondemned()
				{Check(this); return (simulationFlags&CondemnedFlag) != 0;}

	//##########################################################################
	// Transference Support
	//
	public:
		void
			SetTransferableFlag()
				{Check(this); simulationFlags |= TransferableFlag;}
		void
			SetNontransferableFlag()
				{Check(this); simulationFlags &= ~TransferableFlag;}
		Logical
			IsTransferable()
				{Check(this); return (simulationFlags&TransferableFlag) != 0;}

		const EntityID&
			GetEntityID()
				{return entityID;}
		HostID
			GetOwnerID()
				{return ownerID;}

		EntityID
			entityID;
		HostID
			ownerID;

		Player
			*playerLink;

		Player*
			GetPlayerLink()
				{return playerLink;}

	//##########################################################################
	// Interest Support
	//
	public:
		void
			BecomeInteresting();
		void
			BecomeInterestingMessageHandler();
		void
			BecomeUninterestingMessageHandler();

		Logical
			IsInteresting()
				{Check(this); return interestCount != 0;}

		void
			SetInterestLockedFlag();
		void
			SetInterestUnlockedFlag();
		Logical
			IsInterestLocked()
				{Check(this); return (simulationFlags&InterestLockedFlag) != 0;}

		void
			SetInterestZoneID(InterestZoneID interest_zone_ID)
				{interestZoneID = interest_zone_ID;}
		InterestZoneID
			GetInterestZoneID()
				{return interestZoneID;}

		Logical
			IsStatic()
				{Check(this); return (simulationFlags&DynamicFlag) == 0;}
		Logical
			IsDynamic()
				{Check(this); return (simulationFlags&DynamicFlag) != 0;}

		void
			SetTrappedFlag()
				{Check(this); simulationFlags |= TrappedFlag;}
		Logical
			IsTrapped()
				{Check(this); return (simulationFlags&TrappedFlag) != 0;}

		Logical
			IsStatue()
				{Check(this); return (simulationFlags&StatueFlag) != 0;}

		Logical
			IsMap()
				{Check(this); return (simulationFlags&MapFlag) != 0;}

		static Logical
			EntityFlagsIsMap(LWord entity_flags)
				{return (entity_flags&MapFlag) != 0;}

		Type
			GetType()
				{Check(this); return (Type)(simulationFlags&TypeMask);}

		virtual Enumeration
			GetInterestPriority(Entity *linked_entity);

		InterestZoneID
			interestZoneID;
		int
			interestCount;
		Time
			creationTime;

	//##########################################################################
	// Camera Support
	//
	protected:

		Origin
			cameraOffset;

	public:
		Origin
			GetCameraOffset() const
		{Check(this); return cameraOffset; }

	//##########################################################################
	// Scoring support
	//
	public:
      //
      // HACK - ECH 7/6/95 - Allow the player vehicle to respond to score
      // messages, allows attribute system to be used for scoring
      //
      virtual void
      	RespondToScoreMessage(Message *message) {}

	//##########################################################################
	// Construction and Destruction
	//
	public:
		typedef Entity* (*MakeHandler)(MakeMessage *);

		static Entity*
			Make(MakeMessage *creation_message);

		//
		// Warning... This function requires a properly set up strtok!!!!
		//
		static Logical
			CreateMakeMessage(
				MakeMessage *creation_message,
				NotationFile *model_file,
				const ResourceDirectories *directories
			);

		static Logical
			CreateMakeMapMessage(
				MakeMapMessage *creation_message,
				ResourceDescription::ResourceID resource_id,
				NotationFile *model_file,
				const ResourceDirectories *//directories
			);

		static ResourceDescription::ResourceID
			CreateDamageZoneStream(
				ResourceFile 	*resource_file,
				const char 		*model_name,
				NotationFile 	*model_file,
				const ResourceDirectories *directories
			);

		static ResourceDescription::ResourceID
			CreateExplosionTableStream(
				ResourceFile *resource_file,
				const char *model_name,
				NotationFile *model_file,
				const ResourceDirectories *directories
			);

		ResourceDescription::ResourceID
			GetResourceID()
				{Check(this); return resourceID;}
		Player*
			GetOwningPlayer()
         	{Check(this); return owningPlayer;}

		void
			SetupNetworkMessage(Entity::Message *message);

	protected:
		Entity(
			MakeMessage *creation_message,
			SharedData &virtual_data
		);

		ResourceDescription::ResourceID
			resourceID;
		Player
			*owningPlayer;

		void
			DestroyEntityMessageHandler(Message *message);

	public:
		~Entity();

		void
			CondemnToDeathRow();

	//##########################################################################
	// Test Support
	//
	public:
		Logical
			TestInstance() const;
		static Logical
			TestClass();
	};

	inline void
      Entity::SetupNetworkMessage(Entity::Message *message)
      	{
         	Check(this);
				Check(message);
            message->entityID = entityID;
            message->interestZoneID = interestZoneID;
				message->ownerID = ownerID;
			}



#	include <entity3.hpp>
#	undef ENTITY_CONTINUATION

#endif

