//===========================================================================//
// File:	Mission.hpp                                                         //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 02/19/95  JMA  Initial coding.                                            //
// 08/25/97  ECH  Infrastructure changes.                                    //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "EntityClassData.hpp"

namespace gosFX {class Light;}

namespace MidLevelRenderer
{
	class MLRTexture;
	class MLRTexturePool;
};

namespace Adept {

	class Map;

	//##########################################################################
	//##################    Score Object   #####################################
	//##########################################################################

	class ScoreObject:
		public Stuff::Plug
	{
	public:
		ScoreObject(Adept::ReplicatorID id, Stuff::MString name) :
		  Plug(Plug::DefaultData)
		{
			m_playerID = id;
			m_kills = 0;
			m_deaths = 0;
			m_playerName = name;
		}

		~ScoreObject()
			{}

		void AddKill()
			{Check_Object(this); m_kills++;}
		void AddDeath()
			{Check_Object(this); m_deaths++;}

		Adept::ReplicatorID GetID()
			{Check_Object(this); return m_playerID;}
		int GetKills()
			{Check_Object(this); return m_kills;}
		int GetDeaths()
			{Check_Object(this); return m_deaths;}
		
		void SetKills(int kills)
			{Check_Object(this); m_kills = kills;}
		void SetDeaths(int deaths)
			{Check_Object(this); m_deaths = deaths;}

		const char * GetName()
			{Check_Object(this); return (const char *)m_playerName;}

	protected:
		Adept::ReplicatorID
			m_playerID;
		int
			m_kills,
			m_deaths;

		Stuff::MString
			m_playerName;
	};

	//##########################################################################
	//#########################    ArmoryEntry    ##############################
	//##########################################################################

	class ArmoryEntry

	{
	public:
		ResourceID m_resourceID;
		size_t m_count;
	};

	//##########################################################################
	//##################    Mission::CreateMessage    ##########################
	//##########################################################################

	class Mission__CreateMessage:
		public Entity__CreateMessage
	{
	public:
		ResourceID
			m_armoryStreamResourceID,
			m_nameTableStreamResourceID,
			m_skyResourceID,
			m_nightSkyResourceID,
			m_propStreamResourceID,
			m_mapResourceID,
			m_warningBoundsResourceID,
			m_missionBoundsResourceID;
		bool
			m_isNightMission;

		Mission__CreateMessage(
			size_t length,
			int priority,
			int message_flags,
			Stuff::RegisteredClass::ClassID class_id,
			int replicator_flags,
			const ResourceID& instance_id,
			const Stuff::LinearMatrix4D &creation_matrix,
			Stuff::Scalar age,
			int execution_state,
			int name_id,
			int entity_alignment,
			const ResourceID &prop_stream_id,
			const ResourceID &map_id,
			const ResourceID &armory_id,
			const ResourceID &name_table_id,
			const ResourceID &sky_id,
			const ResourceID &night_sky_id,
			const ResourceID &warning_id,
			const ResourceID &mission_id,
			bool is_night
		):
			Entity__CreateMessage(
				length,
				priority,
				message_flags,
				class_id,
				replicator_flags,
				instance_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment
			),
			m_propStreamResourceID(prop_stream_id),
			m_mapResourceID(map_id),
			m_armoryStreamResourceID(armory_id),
			m_nameTableStreamResourceID(name_table_id),
			m_skyResourceID(sky_id),
			m_nightSkyResourceID(night_sky_id),
			m_warningBoundsResourceID(warning_id),
			m_missionBoundsResourceID(mission_id),
			m_isNightMission(is_night)
			{			}

		static void
			ConstructCreateMessage(Script *script);
	};

	//##########################################################################
	//####################    Mission::ModelResource    ########################
	//##########################################################################

	class Mission__GameModel:
		public Entity__GameModel
	{
	public:
		ResourceID
			m_lightStreamResourceID,
			m_nightLightStreamResourceID,
			m_weatherEffectResource,
			m_nightWeatherEffectResource;
		Stuff::RGBAColor
			m_fogColor,
			m_fogColorUnderwater,
			m_fogColorSmoke,
			m_nightFogColor,
			m_nightGroundColor;
		Stuff::Scalar
			m_generalFogStart,
			m_generalFogEnd,
			m_generalFogDensity,
			m_lightFogStart,
			m_lightFogEnd,
			m_lightFogDensity,
			m_customFogStart,
			m_customFogEnd,
			m_customFogDensity,
			m_generalFogStartUnderwater,
			m_generalFogEndUnderwater,
			m_generalFogDensityUnderwater,
			m_lightFogStartUnderwater,
			m_lightFogEndUnderwater,
			m_lightFogDensityUnderwater,
			m_customFogStartUnderwater,
			m_customFogEndUnderwater,
			m_customFogDensityUnderwater,
			m_generalFogStartSmoke,
			m_generalFogEndSmoke,
			m_generalFogDensitySmoke,
			m_lightFogStartSmoke,
			m_lightFogEndSmoke,
			m_lightFogDensitySmoke,
			m_customFogStartSmoke,
			m_customFogEndSmoke,
			m_customFogDensitySmoke,
			m_heightFogStart,
			m_heightFogEnd,
			m_heightFogOpacity,
			m_nearClip,
			m_farClip,
			m_waterSpecularFactor,
			m_waterAtNightSpecularFactor;

		bool
			m_allowRespawn,
			m_allowSearchLights,
			m_allowRunningLights,
			m_canSetTime,
			m_isNightMission;

		int
			m_waterSpecularPower,
			m_waterAtNightSpecularPower;

//		Adept::ResourceID
//			m_animatedTexturesResourceID;

		Stuff::Scalar
			m_heatSinkEfficiency;

		enum {
			GeneralFogStartAttributeID = Entity__GameModel::NextAttributeID,
			GeneralFogEndAttributeID,
			GeneralFogDensityAttributeID,
			LightFogStartAttributeID,
			LightFogEndAttributeID,
			LightFogDensityAttributeID,
			CustomFogStartAttributeID,
			CustomFogEndAttributeID,
			CustomFogDensityAttributeID,
			FogColorAttributeID,
			GeneralFogStartUnderwaterAttributeID,
			GeneralFogEndUnderwaterAttributeID,
			GeneralFogDensityUnderwaterAttributeID,
			LightFogStartUnderwaterAttributeID,
			LightFogEndUnderwaterAttributeID,
			LightFogDensityUnderwaterAttributeID,
			CustomFogStartUnderwaterAttributeID,
			CustomFogEndUnderwaterAttributeID,
			CustomFogDensityUnderwaterAttributeID,
			FogColorUnderwaterAttributeID,
			GeneralFogStartSmokeAttributeID,
			GeneralFogEndSmokeAttributeID,
			GeneralFogDensitySmokeAttributeID,
			LightFogStartSmokeAttributeID,
			LightFogEndSmokeAttributeID,
			LightFogDensitySmokeAttributeID,
			CustomFogStartSmokeAttributeID,
			CustomFogEndSmokeAttributeID,
			CustomFogDensitySmokeAttributeID,
			FogColorSmokeAttributeID,
			AllowRespawnAttributeID,
			WeatherEffectResourceAttributeID,
			AllowSearchLightsAttributeID,
			AllowRunningLightsAttributeID,
			HeightFogStartAttributeID,
			HeightFogEndAttributeID,
			HeightFogOpacityAttributeID,
			NearClipAttributeID,
			FarClipAttributeID,
			NightGroundColorAttributeID,
			CanSetTimeAttributeID,
			NightFogColorAttributeID,
			HeatSinkEfficiencyAttributeID,
			NightWeatherEffectResourceAttributeID,
			WaterSpecularFactorAttributeID,
			WaterAtNightSpecularFactorAttributeID,
			WaterSpecularPowerAttributeID,
			WaterAtNightSpecularPowerAttributeID,
			IsNightMissionAttributeID,
			NextAttributeID
		};

		static void
			ConstructGameModel(Script *script);

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

		static void
			SaveGameModel(
				Mission__GameModel *model,
				Stuff::NotationFile *data_file
			);
	};

	//##########################################################################
	//###########################    Mission    ################################
	//##########################################################################

	typedef Entity__Message							Mission__Message;

	class Mission:
		public Entity
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();
	
		static ClassData
			*DefaultData;

		typedef Mission__Message		Message;
		typedef Mission__CreateMessage	CreateMessage;
		typedef Mission__GameModel		GameModel;

		static Mission*
			GetInstance()
		{
			return reinterpret_cast<Mission *>( GlobalPointers::GetGlobalPointer(MissionGlobalPointerIndex));
		};

		static HGOSHEAP
			s_Heap;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		bool m_FirstFrame;
		static Mission*
			Make(
				const CreateMessage *message,
				ReplicatorID *base_id
			);

		Replicator::CreateMessage*
			SaveMakeMessage(Stuff::MemoryStream *stream, ResourceFile *res_file);
		
		void
			SetUnderwaterFogData();
		void
			SetSmokeFogData();
		void
			BlendSmokeFogData(Stuff::Scalar percentageSmoke);
		void
			ResetNormalFogData();

		void
			TestInstance();

	protected:
		Mission(
			ClassData *class_data,
			const CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);
		~Mission();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Ownership
	//
	public:
		void
			AddChild(Entity *entity);

	protected:
		void
			ChildPreCollisionChanged(Entity *entity);

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

		ResourceID
			propListResourceID;
		ResourceID
			mapResourceID;
		ResourceID
			armoryResourceID;
		ResourceID
			nameTableResourceID;
		ResourceID
			skyResourceID;
		ResourceID
			nightSkyResourceID;

		enum MissionArea {
			InMissionArea,
			InWarningArea,
			OutOfMissionArea
		};
		MissionArea
			GetMissionArea(const Stuff::Point3D &where);
		void
			SetWarningPolygon(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list);
		void
			SetMissionPolygon(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list);
		void
			GetWarningPolygon(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list);
		void
			GetMissionPolygon(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &list);
		void
			AnimateMissionTextures();
		void
			LoadAnimatedTextures(const ResourceID &texture_name_id);
		virtual void
			ResetMissionLights();
		virtual void
			SetLightAmpMissionLights();
//		virtual void
//			SetSearchLightMissionLights();
		void
			SetToNight();
		void
			SetToDay();
		void
			SetDaySky(ResourceID &res);
		void
			SetNightSky(ResourceID &res);
		bool
			DoesAllowRunningLights();
		bool
			DoesAllowSearchLights();

		gosFX::Light*
			GetMainLight()
				{Check_Object(this); return m_mainLight;}
		bool
			AllowRespawn();
		void
			SaveInstanceText(Stuff::Page *page);
		virtual void
			RespawnMission();

	protected:
		Stuff::ChainOf<Entity *> 
			m_respawnProps;

		static bool
			IsInsidePolygon(
				const Stuff::Vector2DOf<Stuff::Scalar> &where,
				Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &polygon
			);

		Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> >
			warningPolygon,
			missionPolygon;

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Scoring Support
	//
	protected:
		Stuff::SortedChainOf<ScoreObject *, Adept::ReplicatorID>
			m_scoringChain;

	public:
		virtual void
// MSL 5.02 headshot
//			ScoringReactToMechDeath(const Adept::ReplicatorID& inflicting_id, const Adept::ReplicatorID& victim_id);
			ScoringReactToMechDeath(const Adept::ReplicatorID& inflicting_id, const Adept::ReplicatorID& victim_id, int damageMode);
		virtual void 
			ScoringReactToTurretDeath (const Adept::ReplicatorID& inflicting_id, const Adept::ReplicatorID& victim_id);
		virtual void
			ScoringReactToBuildingDeath (const Adept::ReplicatorID& inflicting_id, const Adept::ReplicatorID& victim_id);

		virtual void AddScoreMember (const Adept::ReplicatorID& member, const Stuff::MString& name);
		virtual void RemoveScoreMember (const Adept::ReplicatorID& member);
		ScoreObject *GetScoreMember (const Adept::ReplicatorID& member);
		Stuff::SortedChainOf<ScoreObject *,Adept::ReplicatorID>& ScoreChain (void)
		{ return m_scoringChain; }

		bool
			scoreDirty;

		void
			SetScoreDirty(){scoreDirty = true;};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Network visibilty override
	//
		enum {
			DefaultVisibility = 0,
			ClearVisibility = 1,
			LightVisibility = 2,
			HeavyVisibility = 3,
			PeaSoupVisibility = 4
		};


		Scalar
			m_generalFogStart,
			m_generalFogEnd,
			
			m_lightFogStart,
			m_lightFogEnd,
			
			m_customFogStart,
			m_customFogEnd,

			m_heightFogStart,
			m_heightFogEnd,
			m_heightFogOpacity;
			

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Lighting support
	//
	public:
		Stuff::ChainOf<gosFX::Light*>
			m_staticLights;

		Stuff::SlotOf<ElementRenderer::Element*>
			m_sky;
		Stuff::SlotOf<ElementRenderer::Element*>
			m_nightSky;
		gosFX::Light
			*m_mainLight;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private Methods
	//
	public:
		void
			CreateArmoryEntities();
	};

}
