//===========================================================================//
// File:	SRMission.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\Mission.hpp>
#include "abl.h"
#include "aiutils.hpp"
#include "GroupContainer.hpp"
#include "AI_Log.hpp"
#include "MW4AnimationSystem.hpp"
#include "Mech.hpp"
#include "HeatManager.hpp"
#include "VehicleInterface.hpp"
#include "SensorCellMap.hpp"
#include "AI_DebugRenderer.hpp"
#include "path.hpp"

#include "MLR\MLRMovieTexture.hpp"

//#include "bucket.hpp"

namespace MidLevelRenderer
{
	class MLRTexture;
	class MLRTexturePool;
};

namespace MechWarrior4
{
	class CBucketManager;

	class Narc;

	//##########################################################################
	//########################    Reaction Sphere    ###########################
	//##########################################################################

	class ReactionSphere:
		public Stuff::Plug
	{
	public:
		ReactionSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs):
			Plug(Plug::DefaultData)
		{
			m_sphere.center = center;
			m_sphere.radius = radius;
			m_endTime = gos_GetElapsedTime() + secs;
			m_hasRun = false;
			m_markedOnce = false;

			//By entering the time to be 0.0f will cause it to be a one time thing!
			if(secs <= 0.0f)
				m_markedOnce = true;
		}

		~ReactionSphere(){}

		Stuff::Time
			GetEndTime()
				{Check_Object(this); return m_endTime;}
		void
			SetHasRun()
				{Check_Object(this); m_hasRun = true;}
		bool
			DoesEffect(const Stuff::Point3D& target_point)
				{Check_Object(this); SetHasRun(); return m_sphere.Contains(target_point);}
		virtual void
			ApplyEffect(Mech *mech){}
		bool
			IsOver()
		{
			Check_Object(this); 
			if(m_markedOnce)
				return m_hasRun;
			return gos_GetElapsedTime() >= GetEndTime();
		}

	private:
		Stuff::Sphere
			m_sphere;
		Stuff::Time
			m_endTime;
		bool
			m_markedOnce;
		bool
			m_hasRun;
	};

	//##########################################################################
	//######################   Instance Heat Sphere    #########################
	//##########################################################################

	class InstantHeatReactionSphere:
		public ReactionSphere
	{
	public:
		InstantHeatReactionSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs, Stuff::Scalar amount):
			ReactionSphere(center, radius, secs)
		{
			m_heatAmount = amount;
		}

		~InstantHeatReactionSphere(){}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// 
		void
			ApplyEffect(Mech *mech) 
		{
			Check_Object(this);
			
			mech->m_heatManager->AddHeat(m_heatAmount);
		}

	private:
		Stuff::Scalar
			m_heatAmount;

	};

	//##########################################################################
	//######################   Reaction Heat Sphere    #########################
	//##########################################################################

	class HeatReactionSphere:
		public ReactionSphere
	{
	public:
		HeatReactionSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs, Stuff::Scalar percent):
			ReactionSphere(center, radius, secs)
		{
			m_heatEfficiency = percent;
		}

		~HeatReactionSphere(){}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// 
		void
			ApplyEffect(Mech *mech) 
		{
			Check_Object(this);
			
			mech->m_heatMaterialMultiplier += m_heatEfficiency;
		}

	private:
		Stuff::Scalar
			m_heatEfficiency;

	};

	//##########################################################################
	//#######################   Fog Reaction Sphere    #########################
	//##########################################################################

	class FogReactionSphere:
		public ReactionSphere
	{
	public:
		FogReactionSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs):
			ReactionSphere(center, radius, secs)
		{
		}

		~FogReactionSphere(){}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// 
		void
			ApplyEffect(Mech *mech) 
		{
			Check_Object(this);
		
			mech->vehicleInterface->fNeedSmoke = true;
		}
	};

	//##########################################################################
	//######################   Radar Reaction Sphere    ########################
	//##########################################################################

	class RadarReactionSphere:
		public ReactionSphere
	{
	public:
		RadarReactionSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs, Stuff::Scalar percent):
			ReactionSphere(center, radius, secs)
		{
			m_radarMultiplier = percent;
		}

		~RadarReactionSphere(){}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// 
		void
			ApplyEffect(Mech *mech) 
		{
			Check_Object(this);
			
			mech->m_sensorDinstanceMultiplier += m_radarMultiplier;
		}

	private:
		Stuff::Scalar
			m_radarMultiplier;

	};

	const int MAX_MISSION_TIMERS = 32;


	//##########################################################################
	//##################    MWMission::CreateMessage    ########################
	//##########################################################################

	class MWMission__CreateMessage:
		public Adept::Mission__CreateMessage
	{
	public:
		ResourceID railgraphStreamResourceID;
		char scriptName[128];
		Scalar distanceCheck;

		MWMission__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 Adept::ResourceID &prop_stream_id,
			const Adept::ResourceID &map_id,
			const Adept::ResourceID &armory_id,
			const Adept::ResourceID &name_table_id,
			const Adept::ResourceID &sky_id,
			const Adept::ResourceID &night_sky_id,
			const ResourceID &warning_id,
			const ResourceID &mission_id,
			bool is_night,
			const Adept::ResourceID &rail_graph_id,
			const char *script_name,
			Scalar distance_check

		):
			Adept::Mission__CreateMessage(
				length,
				priority,
				message_flags,
				class_id,
				replicator_flags,
				instance_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment,
				prop_stream_id,
				map_id,
				armory_id,
				name_table_id,
				sky_id,
				night_sky_id,
				warning_id,
				mission_id,
				is_night
			),
			railgraphStreamResourceID(rail_graph_id),
			distanceCheck (distance_check)
			{
				Check_Pointer(script_name);
				scriptName[0] = 0;
				Str_Copy(scriptName, script_name, sizeof(scriptName));
			}

		static void
			ConstructCreateMessage(Script *script);
	};

	//##########################################################################
	//####################    MWMission::ModelResource    ######################
	//##########################################################################

	class MWMission__GameModel:
		public Adept::Mission__GameModel
	{
	public:
		
		Adept::ResourceID
			m_animatedTexturesResourceID,
			m_movieTexturesResourceID;

		static void
			ConstructGameModel(Script *script);

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

	};

	//##########################################################################
	//##########################    MWMission    ###############################
	//##########################################################################

	class MWMission:
		public Adept::Mission
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance Support
	//
		typedef MWMission__CreateMessage					CreateMessage;
		typedef MWMission__GameModel						GameModel;

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

		void
			RespawnMission();

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

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

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

		Stuff::ChainOf<Entity *>	m_CheckChain;
		Stuff::Scalar m_DistanceCheck;

		
		void
			PreCollisionExecute(Stuff::Time till);

		

		void ABLConstNameTable (void);

		char scriptName[128];
		long									missionScriptHandle;
		ABL::ABLModulePtr			missionBrain;
		void UnloadScript (void);
		bool ReloadScript (ABL::ABLError *err);
		static bool	ReloadABL(ABL::ABLError *err);
		static void UnloadABL(void);
		ABL::ABLModulePtr	Brain (void)
		{ return missionBrain; }

		void
			ResetMissionLights();
		void
			SetLightAmpMissionLights();

	//-----------------------
	//Reaction Sphere support
	//-----------------------
	public:
		//This one is used by mechs who are checking
		void
			ProcessReactionSpheres(Mech *target_mech);
		void
			ProcessPlayerReactionSpheres(Mech *target_mech);
		//This one is used by mission to resolve which ones can stay
		void
			ResolveReactionSpheres();
		void
			CreateNewHeatSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs, Stuff::Scalar heat_e);
		void
			CreateNewInstantHeatSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar heat_amount);
		void
			CreateNewRadarSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs, Stuff::Scalar radar_e);
		void
			CreateNewFogSphere(const Stuff::Point3D& center, Stuff::Scalar radius, Stuff::Scalar secs);

		Stuff::ChainOf<ReactionSphere *>
			m_reactionSpheres;
		Stuff::ChainOf<ReactionSphere *>
			m_playerOnlyReactionSpheres;

	//------------
	//Flag settings Support
	//------------
	public:
		enum FLAG_ENABLE_STATE
		{
			// NOTE: these must EXACTLY match the constants in MWCONST.ABI
			FLAGS_HIDE				= 0x0,
			FLAGS_TEAM_ONLY			= 0x1,
			FLAGS_UNIVERSAL_ONLY	= 0x2,
			FLAGS_SHOW_ALL			= 0x3
		};

		void
			SetMaxFlagsCarried(int max_flags)
				{	m_MaxFlagsCarried = max_flags;	}

		int
			GetMaxFlagsCarried() const
				{	return (m_MaxFlagsCarried);		}

		void
			SetFlagDropReturnTime(int return_time)
				{	m_FlagDropReturnTime = return_time;	}

		int
			GetFlagDropReturnTime() const
				{ return (m_FlagDropReturnTime);		}

		void
			SetFlagCaptureReturnTime(int return_time)
				{	m_FlagCaptureReturnTime = return_time;	}

		int
			GetFlagCaptureReturnTime() const
				{	return (m_FlagCaptureReturnTime);	}

		void
			SetFlagsEnabled(FLAG_ENABLE_STATE state)
				{	m_FlagsEnabled = state;	}

		bool
			GetFlagCaptureEnabled() const
				{	return (m_FlagCaptureEnabled);	}

		void
			SetFlagCaptureEnabled(bool enabled)
				{	m_FlagCaptureEnabled = enabled;		}

		FLAG_ENABLE_STATE
			GetFlagsEnabled() const
				{	return (m_FlagsEnabled);	}

		void
			SetFlagsAsNavPoints(bool show)
				{	m_FlagsAsNavPoints = show;	}

		bool
			GetFlagsAsNavPoints() const
				{	return (m_FlagsAsNavPoints);	}

	private:
		int
			m_MaxFlagsCarried;
		int
			m_FlagDropReturnTime;
		int
			m_FlagCaptureReturnTime;
		FLAG_ENABLE_STATE
			m_FlagsEnabled;

		bool
			m_FlagCaptureEnabled;

		bool
			m_FlagsAsNavPoints;

	//------------
	//Narc Support
	//------------
	public:
		void
			AddNarc(Narc *narc, int alignment);
		Narc
			*GetNarc(int alignment);

		Stuff::SortedChainOf<Narc *, int>
				m_narcs;

		SensorCellMap
			m_VehicleAndTurretCellMap;

		SensorCellMap
			m_BuildingCellMap;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Public Data
	//
	protected:
		MW4AI::CTimeServer m_Timers[MAX_MISSION_TIMERS];

		MW4AI::CTimeServer m_EndMissionTimer;
		MW4AI::CTimeServer m_missionTimer;

		Stuff::Scalar m_EndTime;

		GroupContainer
			m_GroupContainer;

		MW4AI::DiagnosticsInterface
			m_DiagnosticsInterface;

		bool m_MissionSuccess;
		Stuff::ChainOf<AI *> m_LancemateChain;

		void DisconnectLancemates (void);
		void CreateLancemateGroups ();
		void AddToLancemateGroup(Mech* lancemate, int team_number);

	private:
		Stuff::Scalar
			m_LastNavRefresh;

	public:
		void AddLancemate (AI *lancemate);
		CBucketManager *m_BucketManager;

		MW4AI::CTimeServer& Timer (int id)
		{
			Verify (id >= 0);
			Verify (id<MAX_MISSION_TIMERS);
			return m_Timers[id];
		}
		void EndMissionState (bool succeeded);
		bool EndMissionState (void) const
		{ return m_MissionSuccess;  }

		void SetEndMissionTime (Stuff::Scalar seconds);

		void SetNetworkTime (Stuff::Scalar seconds)
		{
			m_EndMissionTimer.SetTime(seconds);
		}


		void StartMissionTimer()
		{
			m_missionTimer.Start();
		}

		bool EndMissionTimerRunning()
		{
			return (m_EndMissionTimer.Running());
		}
		
		//sanghoon
		Stuff::Scalar GetMissionDuration ()
		{
			if (!m_EndMissionTimer.Running ())
				return 0;
			
			return m_EndTime;
		}

		Stuff::Scalar GetEndMissionTime ()
		{
			if (!m_EndMissionTimer.Running ())
				return 0;
			
			return m_EndTime - (Stuff::Scalar)m_EndMissionTimer.CurrTime();
		}

		Stuff::Scalar GetMissionTime ()
		{
			if (!m_missionTimer.Running ())
				return 0;
			
			return (Stuff::Scalar)m_missionTimer.CurrTime();
		}


		Scalar lastShutdownTest;
		Scalar shutDownTimer;
		bool TestForGameShutDown(ReplicatorID victim_id);
		bool TestForGameShutDownUnlimitedRespawn();

// MSL 5.02 headshot
//		virtual void ScoringReactToMechDeath(const Adept::ReplicatorID& inflicting_id, const Adept::ReplicatorID& victim_id);
		virtual void 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);

		virtual void
			SaveInstanceText(Stuff::Page *page);

		GroupContainer&
			GetGroupContainer();
		const GroupContainer&
			GetGroupContainer() const;

		MW4AI::DiagnosticsInterface&
			GetDiagnosticsInterface();
		const MW4AI::DiagnosticsInterface&
			GetDiagnosticsInterface() const;

		int
			m_ChanceLancematesEject;
		int
			m_ChanceLancematesOKWhenEjecting;
		int
			m_ChanceLancematesInjuredWhenEjecting;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
		Stuff::Point3D
			m_ConstraintTopLeft;

		Stuff::Point3D
			m_ConstraintBottomRight;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture Animation Support
	//
	public:
		void
			InitializeTextureAnimations(const Adept::ResourceID& anim_resource_id);
		void
			PlayAnimations(Stuff::Scalar time_slice);
		void
			PlayTextureMovies(Stuff::Scalar time_slice);
		static int
			FindIndex(
				const char *joint_name,
				void *user_data
			);
		static void
			ApplyChannel
			(
				MW4Animation::ChannelApplication &channel_data,
				int joint_index,
				void *user_data
			);

		Stuff::DynamicArrayOf<PlugOf<MString> *>
			animatedTextureNames;
		Stuff::DynamicArrayOf<MidLevelRenderer::MLRTexture *>
			animatedTextures;
		Stuff::DynamicArrayOf<Stuff::Scalar>
			animatedTexturesMultipliers;
		Stuff::ChainOf<MW4Animation::AnimInstance *>
			m_textureAnimInstances;
		Stuff::ChainOf<MW4Animation::AnimIterator *>
			m_textureAnimIterators;
		MW4Animation::AnimHierarchyIteratorManager
			*iteratorManager;
		int
			m_numberOfAnims;

		Stuff::DynamicArrayOf<PlugOf<MString> *>
			movieTextureNames;
		Stuff::DynamicArrayOf<MidLevelRenderer::MLRMovieTexture *>
			movieTextures;
		Stuff::DynamicArrayOf<Stuff::Scalar>
			movieTexturesFrameTime;

		int
			m_numberOfMovies;

		MW4AI::DebugRenderer m_AIDebugRenderer;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Coliseum Support
	//
	private:
		int
			m_missionType;

	public:
		enum {
			MISSIONTYPE_UNSPECIFIED=0,
			MISSIONTYPE_ARCTIC,
			MISSIONTYPE_SWAMP,
			MISSIONTYPE_HOTPLATE,
			MISSIONTYPE_COLISEUM,
			MISSIONTYPE_FACTORY,
			MISSIONTYPE_JUNGLE
		};
		int
			GetMissionType()
				{ return m_missionType;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture Animation Support
	//

		void
			InitializeTextureMovies(const Adept::ResourceID& movie_resource_id);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		enum {
			StartMusicStatusAttributeID=0,
			TransMusicStatusAttributeID,
			NumMissionAttributes
		};

	public:
		//
		// Attributes
		//
		int startMusicStatus;
		int transMusicStatus;

	public: // jcem - 30/60 seconds to mission termination
        bool m_b30notified;
        bool m_b60notified;
    public: // jcem - no abrupt ending for "No Return" game...
        Stuff::Scalar m_fShouldBeStopped;
    public: // jcem - no abrupt ending for "No Return" game...
        Stuff::Scalar CheckEndMissionTime ();
    protected: // jcem - no abrupt ending for "No Return" game...
        bool real_TestForGameShutDown(ReplicatorID victim_id); // jcem
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      	TestInstance() const;
	public: // jcem
		bool m_bOrgBoundsStored;
		bool m_bBoundsWarningsEnabled;
		Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> >
			m_warningPolygonOld,
			m_missionPolygonOld;
		Stuff::Point3D m_ConstraintTopLeftOld;
		Stuff::Point3D m_ConstraintBottomRightOld;
	public: // jcem
		void StoreOriginalBounds();
		void RestoreOriginalBounds();
		void SetBoundsFromPaths(const MechWarrior4::Path& PathMission, const MechWarrior4::Path& PathWarning);
    public: // COOP <-> ablxstd <-> *.abl
        enum {
            COOP_MISC_START = 0,
            MAX_COOP_MISCS = 100,

            COOP_SUBSTAGE_SCORE_OLD,

            COOP_ENEMY_GROUP,
            COOP_ENEMY_GROUP_OLD,

            COOP_MODAL_START,
            COOP_MODAL_IS_ENDED,

            COOP_SUBSTAGE_TIMEGOAL,
            COOP_SUBSTAGE_NUMBER,

            MAX_COOP_VARS,
        };
        int m_naCOOPs[MAX_COOP_VARS];
    public:
        void InitCOOP();
        void ExitCOOP();
        int GetCOOP(int nIdx, void* pDest = (void*)NULL);
        int SetCOOP(int nIdx, int nParam);
	};
}

