//===========================================================================//
// File:	DamageObject.hpp                                                    //
// Project: Adept           Brick: DamageObject	                             //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 03/08/99  DPB  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1998-1999, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Receiver.hpp"
#include "Entity.hpp"

namespace Adept
{


	void __cdecl AdeptDamageSecurityCheckStart(void);
	void __cdecl AdeptDamageSecurityCheckStop(void);


	extern HGOSHEAP
		g_DamageObjectHeap;

// MSL 5.03 Lava
	enum
	{
		BeamDamageType = 0,
		MissileDamageType,
		ProjectileDamageType,
		SplashDamageType,
		HeatDamageType,
		RammingDamageFromAboveType,
		RammingDamageFromBelowType,
		RammingDamageFromLeftType,
		RammingDamageFromRightType,
		RammingDamageFromAheadType,
		RammingDamageFromBehindType,
		HighExplosiveDamageType,
		LavaDamageType,
		AmmoFireDamageType

	};

	class Effect;
	class InternalDamageObject;
	class Site;

	class DamageEffectObject
	{
	public:
		Adept::ResourceID resourceID;
		Stuff::Scalar armorPercent;
	};


	typedef Receiver__ClassData				InternalDamageObject__ClassData;
	typedef Receiver__Message				InternalDamageObject__Message;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Internal Damage Object class
	//
	class InternalDamageObject:
		public Receiver
	{
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance Support
	//
	public:
		typedef InternalDamageObject__ClassData			ClassData;
		typedef InternalDamageObject__Message			Message;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction, Testing
	//
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static void
			ConstructInternalDamageObjectStream(
				Stuff::MemoryStream *stream,
				Stuff::Page *instance_page,
				Stuff::RegisteredClass::ClassID class_id = DefaultData->GetClassID()
			);

		virtual void
			Save(MemoryStream *stream,
				Stuff::RegisteredClass::ClassID class_id = DefaultData->GetClassID());

		InternalDamageObject(
			ClassData *class_data,
			Stuff::MemoryStream *stream
		);

		~InternalDamageObject();

		void
			Reuse();
		void
      		TestInstance();
	
		void*
			operator new(size_t);
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation support
	//

	public:

		virtual Scalar
			TakeDamage(Stuff::Scalar damage_taken, Entity__TakeDamageMessage *message);
		virtual void
			InflictCriticalHit()
				{}

		ResourceID
			GetDamageEffectID();

		void
			PlayDamageEffects(Entity__TakeDamageMessage *message);
		
		Stuff::Scalar
			baseInternalDamage,
			currentInternalDamage;
		Scalar *m_HitPointPointer;
		void SetHitPointPointer (Scalar *m_HitPoints)
		{ m_HitPointPointer = m_HitPoints; }

		Stuff::DynamicArrayOf<DamageEffectObject>
			damageEffects;

		ResourceID
			currentDamageEffectResourceID;
		Effect
			*currentDamageEffect;
		
		
		// visual damage types..
		// currently we only use
		// normal and destroyed
		// normal = regular geometry
		// damaged = darkened
		// destroyed = destroyed geometry
		// desimated = no geometry

		// this is for network support

		enum {
			NoDamage = 0,
			Damaged,
			Destroyed,
			Desimated
		};

		int GetCurrentDamageLevel();
		void SetCurrentDamageLevel(int level);

		Scalar GetHighResDamageLevel();
		void SetHighResDamageLevel(Scalar damage_percentage);

		void SilentDestruction();

		bool CanRepair()
			{Check_Object(this); return GetCurrentDamageLevel() == Damaged;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Entity Interaction Support
	//
	public:
		enum {
			GeneralDamageMode = 0,
			GimpLeftDamageMode,
			GimpRightDamageMode,
			DestructionDamageMode,
			DetachableDamageMode,
			EngineDamageMode,
			NextDamageMode,
// MSL 5.02 headshot
			HeadShotDamageMode,
// MSL 5.03 Gyro Hit
			GyroHitDamageMode,
// MSL 5.05 Torso
			TorsoLeftDamageMode,
			TorsoRightDamageMode,
			ArmLeftDamageMode,
			ArmRightDamageMode,
		};

		enum {
			NullZone=-1,
			LeftLegZone = 0,	//Mech pieces must follow default zone
			RightLegZone,
			LeftArmZone,
			RightArmZone,
			RightTorsoZone,
			LeftTorsoZone,
			CenterTorsoZone,
			HeadZone,
			SpecialZone1,
			SpecialZone2,
			VehicleHullZone, //All Vehicle and non-mech zones must be after the specials
			VehicleWeaponZone,
			VehicleSpecialZone,
			DefaultZone,
			NextDamageZone
		};

		enum{
			StandardInternal = 0,
			EndoSteelInternal,
			TypeCount
		};

		enum{
			DefaultInternalType = StandardInternal
		};

		void
			Initialize(Entity *entity);

		static int
			DamageModeTextToAscii(const char *mode_name);
		static const char *
			DamageModeAsciiToText(int damage_mode);
		static int
			InternalZoneTextToAscii(const char *mode_name);
		static const char *
			InternalZoneAsciiToText(int internal_zone);

		void
			SetType(int new_type);

		Entity
			*parentEntity;
		InternalDamageObject
			*damagePropagationObject;
		int
			damagePropagationZoneID;
		int
			damageMode;
		int
			damageZone;
		MString
			parentEntityName;
		Stuff::Time
			m_firstHitTime;

// MSL 5.02 headshot
		bool
			m_headShotFlag; //damage mode is really head shot damage mode when true.

// MSL 5.03 Gyro Hit
		bool
			m_gyrohitFlag; //damage mode is really head shot damage mode when true.

		int
			m_internalType;

		//Used only if we are a special zone.
		int
			m_specialConnectedTo;

		Site*
			GetNextWeaponSite();
		Site*
			GetNextEjectSite();

		Stuff::SortedChainOf<Site *, MString> m_sites;
		// The same sites were being returned for each call. The iterators
		// are now seperated into a weapon port iterator and and eject port
		// iterator. Added this change to Vengeance, too --CBT 1/10/2002
		Stuff::SortedChainIteratorOf<Site *, MString> m_weaponSiteIterator;
		Stuff::SortedChainIteratorOf<Site *, MString> m_ejectionSiteIterator;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Receiver__ClassData				DamageObject__ClassData;
	typedef Receiver__Message				DamageObject__Message;

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

	class DamageObject:
		public Receiver
	{
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance Support
	//
	public:
		typedef DamageObject__ClassData			ClassData;
		typedef DamageObject__Message			Message;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction, Testing
	//
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static void
			ConstructDamageObjectStream(
				Stuff::MemoryStream *stream,
				Stuff::Page *instance_page
			);

		virtual void
			Save(MemoryStream *stream);

		DamageObject(
			ClassData *class_data,
			Stuff::MemoryStream *stream
		);

		~DamageObject();

		void Reuse();

		void
      		TestInstance();
	
		void*
			operator new(size_t);
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation support
	//
	public:
		virtual void
			TakeDamage(Entity__TakeDamageMessage *message, Entity *entity_hit);
		
		Stuff::Scalar
			baseArmorValue,
			currentArmorValue,
			scaleSplashDamage,
			maxArmorValue;
		
		enum {
			NullArmorZone=-1,
			LeftLegArmorZone = 0,
			RightLegArmorZone,
			LeftArmArmorZone,
			RightArmArmorZone,
			RightTorsoArmorZone,
			LeftTorsoArmorZone,
			CenterTorsoArmorZone,
			CenterRearTorsoArmorZone,
			HeadArmorZone,
			SpecialArmorZone1,
			SpecialArmorZone2,
			DefaultArmorZone
		};

		static int
			ArmorZoneTextToAscii(const char *armor_name);
		static const char *
			ArmorZoneAsciiToText(int armor_zone);

		enum {
			NoArmorDamage = 0,
			PartialArmorDamage,
			MediumArmorDamage,
			BadArmorDamage,
			ArmorDestroyedDamage,
			InternalDestroyedDamage
		};

		enum{
			StandardArmor = 0,
			FerroFiberusArmor,
			ReactiveArmor,
			ReflectiveArmor,
			SolarianArmor,
			TypeCount
		};

		enum{
			DefaultArmorType = StandardArmor
		};

		// visual damage types..
		// currently we only use
		// normal and destroyed
		// normal = regular geometry
		// damaged = darkened
		// destroyed = destroyed geometry
		// desimated = no geometry

		// this is for network support

		enum {
			NoDamage = 0,
			Damaged,
			Destroyed,
			Desimated
		};

		int GetCurrentDamageLevel();
		
		void SetCurrentDamageLevel(int level);

		// Fix Bug #3100 
		// Damage Object are now refreshed when a mech sustains internal damage

		void RefreshCurrentDamageLevel();

		Scalar GetHighResDamageLevel();
		void SetHighResDamageLevel(Scalar damage_percentage);

		void SilentDestruction();

		bool CanRepair();
			
	public:
		enum {
			DmgModifier_Default = 0,
			DmgModifier_Splash,
			DmgModifier_Count,
		};
	protected:
		// from here by jcem
		Stuff::Scalar m_aDamageModifier[DmgModifier_Count * 2]; // (Modifier & Safety)*
		// to here by jcem
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Entity Interaction Support
	//
	public:
		// from here by jcem
		Stuff::Scalar GetDamageModifier (int nIdx) const;
		void SetDamageModifier (int nIdx, Stuff::Scalar newvalue);
		// to here by jcem

		void
			Initialize(Entity *entity);
		void
			SetDamageArrayEntry(int *array_entry)
				{Check_Object(this); damageArrayEntry = array_entry;}
		void
			SetArmorArrayEntry(Scalar *array_entry)
				{Check_Object(this); armorArrayEntry = array_entry;}
		int
			DetermineDamageLevel();
		void
			SetType(int new_type);
		void
			AppendArmor(Stuff::Scalar additive_armor);

		Entity
			*parentEntity;
		InternalDamageObject
			*internalDamageObject;
		int
			internalDamageObjectID;
		MString
			damageObjectName;
		int
			armorZone;
		int
			*damageArrayEntry;
		Scalar *armorArrayEntry;
		Scalar *m_HitPointPointer;
		void SetHitPointPointer (Scalar *m_HitPoints)
		{ m_HitPointPointer = m_HitPoints; }

		int
			damageLevel;
		Scalar armorLevel;
		int
			m_armorType;
		int
			m_specialConnectedToZone;

		//
		// There is a problem when splash damage hits multiple entities that share a single damage zone.
		//
		bool
			m_fTakenDamageFromThisEvent;

		void
			SetTakenDamageFromThisEvent() {m_fTakenDamageFromThisEvent = true;}
		void
			ClearTakenDamageFromThisEvent() {m_fTakenDamageFromThisEvent = false;}
		bool
			GetTakenDamageFromThisEvent() {return m_fTakenDamageFromThisEvent;}
    public:
        void RefrehDamageState(); // jcem
        void RepairDamage(Scalar fRepair);
	};


	
}

