//===========================================================================//
// File:	damage.hpp                                                          //
// Project: MUNGA           Brick: Entity Manager                            //
// Contents: Damage Definitions							                          //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 05/01/95  JM   Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#if !defined(DAMAGE_HPP)
#	define DAMAGE_HPP

#	if !defined(POINT3D_HPP)
#		include <point3d.hpp>
#	endif

#	if !defined(NODE_HPP)
#		include <node.hpp>
#	endif

#	if !defined(NORMAL_HPP)
#		include <normal.hpp>
#	endif

#	if !defined(CSTR_HPP)
#		include <cstr.hpp>
#	endif

#	if !defined(TABLE_HPP)
#		include <table.hpp>
#	endif

#	if !defined(SCHAIN_HPP)
#		include <schain.hpp>
#	endif

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

	class MaterialList;
	class EntitySegment;
	class ExplosionTable;
	class Simulation;
	class MemoryStream;
	class NotationFile;
	class ResourceDirectories;
	class Entity;

	//##########################################################################
	//###########################    Damage    #################################
	//##########################################################################

	class Damage
	{
	public:
		enum {
			CollisionDamageType,
			BallisticDamageType,
			ExplosiveDamageType,
			LaserDamageType,
			EnergyDamageType,
			DamageTypeCount
		};
      Enumeration
			damageType;
		Scalar
			damageAmount;

		Vector3D
			damageForce;
		Normal
			surfaceNormal;

		// impact point should be in the global coordinate space.
		Point3D
			impactPoint;
		//
		// burst count should be thought of as number of times
		// to apply the damage.  
		//

		int
			burstCount;


		Damage();
	};

	//##########################################################################
	//#########################    MaterialList    #############################
	//##########################################################################

	class MaterialList :
		public Plug
	{
		public:

			typedef PlugOf<CString> CStringPlug;

			typedef SChainOf<CStringPlug*>
				CStringSocket;

			typedef SChainIteratorOf<CStringPlug*>
				CStringSocketIterator;

   	protected:

			CStringSocketIterator*
				listIterator;

			CStringSocket
				materialList;

		public:

			MaterialList();
			~MaterialList();

			void
				DeletePlugs()
			{Check(this); listIterator->DeletePlugs();}

			void
				Add(CStringPlug *new_plug)
			{Check(this); materialList.Add(new_plug);}

			void
				First()
			{	Check(this);listIterator->First();}

			void
				Last()
			{Check(this); listIterator->Last(); }

			CString*
				ReadAndNext()
			{
				Check(this);
				if (!listIterator->GetCurrent())
					return NULL;
				else
					return listIterator->ReadAndNext()->GetPointer();
			}

			CString*
				GetCurrent()
			{
				Check(this);
				if (!listIterator->GetCurrent())
					return NULL;
				else
					return listIterator->GetCurrent()->GetPointer();
			}

			void
				Next()
			{Check(this); if(listIterator->GetCurrent()) listIterator->Next();}
	};
   //##########################################################################
	//#################    DamageZone::UpdateRecord    #########################
	//##########################################################################

	struct DamageZone__UpdateRecord
	{
		public:
			size_t recordLength;
         int	damageZoneIndex;
         Scalar damageLevel;
			Enumeration damageZoneState;
			Enumeration damageZoneGraphicState;
         LWord	changedFlags;
	};

	//##########################################################################
	//#########################    DamageZone    ###############################
	//##########################################################################

	class DamageZone:
		public Node
	{
	protected:

		Simulation*
			owningSimulation;
   
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State Support
	//
	private:

		StateIndicator
				damageZoneState;

      StateIndicator
				damageZoneGraphicState;

	public:

		enum{
				ExistsGraphicState = 0,
				DestroyedGraphicState,
				GoneGraphicState,
            GraphicStateCount
			};

			enum{
				DefaultState = 0,
				BurningState,
				DamageStateCount
			};

      StateIndicator*
				GetGraphicStatePointer()
			{Check(this); return &damageZoneGraphicState;}

		Enumeration
				GetDamageZoneState()
				{Check(this); return damageZoneState.GetState();}

		void
				SetDamageZoneState(Enumeration new_state)
				{Check(this); damageZoneState.SetState(new_state); }

      Enumeration
				GetGraphicState()
				{Check(this); return damageZoneGraphicState.GetState();}

		virtual void
				SetGraphicState(Enumeration new_state)
           {
					Check(this);
					damageZoneGraphicState.SetState(new_state);
					SetGraphicStateChangedFlag();
			  }

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Flag Support
	//

	public:

		enum {
			DamageLevelChangedBit = 2,
			GraphicStateChangedBit,
			NextBit
		};

		enum {
			DamageLevelChangedFlag = 1 << DamageLevelChangedBit,
			GraphicStateChangedFlag = 1 << GraphicStateChangedBit
		};

		Logical
			DamageLevelChanged() const
		{Check(this); return (changedFlags & DamageLevelChangedFlag); }

      Logical
			GraphicStateChanged() const
		{Check(this); return (changedFlags & GraphicStateChangedFlag); }

		void
			SetDamageLevelChangedFlag()
		{Check(this); changedFlags |= DamageLevelChangedFlag; }

		void
			SetGraphicStateChangedFlag()
		{Check(this); changedFlags |= GraphicStateChangedFlag; }

		void
			ResetChangedFlags()
		{Check(this); changedFlags = 0; }

		LWord
			changedFlags;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Update Support
	//
	public:
		typedef DamageZone__UpdateRecord UpdateRecord;

		virtual void
			ReadUpdateRecord(UpdateRecord *message);

		virtual void
			WriteUpdateRecord(UpdateRecord *message);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Material Support
	//

	public:
		typedef TableOf<MaterialList*, Enumeration>
			MaterialTable;

		typedef TableIteratorOf<MaterialList*, Enumeration>
			MaterialTableIterator;

		MaterialList*
			GetMaterialList(Enumeration skl_type)
			{
				Check(this);
				return materialTable.Find(skl_type);
			}

     protected:
   	
		MaterialTable
			materialTable;

   
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Explosion Support
	//

	protected:

		ExplosionTable
			*explosionTable;

	public:

		ExplosionTable*
			CreateExplosionTable(MemoryStream *explosion_stream);

		ExplosionTable*
			GetExplosionTable()
		{Check(this); return explosionTable; }

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Effect Support
	//
	public:
		SChainOf<EntitySegment*>
			defaultEffectSiteChain,
			internalVideoEffectSiteChain,
			externalVideoEffectSiteChain,
			internalAudioEffectSiteChain,
			externalAudioEffectSiteChain;

		enum {
			DefaultEffectSite,
			ExternalVideoEffectSite,
			InternalVideoEffectSite,
			ExternalAudioEffectSite,
			InternalAudioEffectSite,
			EffectSiteCount
		};

		EntitySegment*
			GetCurrentEffectSite(Enumeration	effect_site_type = DefaultEffectSite);

		static
			WriteEffectSegmentIndicies(
				MemoryStream	*damage_zone_stream,
				const char		*damage_zone_name,
				NotationFile	*dmg_file,
				NotationFile	*skl_file,
				const char		*effect_type
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local Support
	//
	public:

   	Simulation*
			GetOwningSimulation()
				{return owningSimulation;}

		int
			damageZoneIndex;

		Scalar
			defaultArmorPoints;

		Scalar
			damageScale[Damage::DamageTypeCount];

		Scalar
			damageLevel;

		CString damageZoneName;

		virtual void
			TakeDamage(Damage &damage);

		void
			Reset(Logical full_reset=True);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction / Destruction Support
	//
		DamageZone(
			Simulation		*owner,
			int				damage_zone_index,
			MemoryStream	*dzone_res
		);

		DamageZone(Simulation *owner, int damage_zone_index);

		virtual ~DamageZone();

		Logical
			TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Resource Support
	//
		static Logical
			CreateStreamedDamageZone(
				NotationFile					*model_file,
				const char 						*model_name,
            NotationFile					*skl_file,
				CString							damage_zone_name,
				MemoryStream					*damage_zone_stream,
				NotationFile					*dmg_file,
				const ResourceDirectories	*directories
			);
	};


#endif
