// CSpectatorStateEngine.hpp *****************************************//
// Created     Owner     Modification                                //
// Copyright Microsoft Corporation, 2001                             //
// --------    ------    -------------                               //
// 12/12/2001  sdemar    provides FSM for spectator camera mgt       //
//*******************************************************************//

#if !defined(MSR_SPECTATOR_STATE_ENGINE_)
#define MSR_SPECTATOR_STATE_ENGINE_

#include "SpectatorTimer.hpp"
#include "MW4\MW4Headers.hpp"
#include <MW4\Mech.hpp>
// #include "MWApplication.hpp"
// #include <MW4\MW4.hpp>
#include "Adept\GlobalPointerManager.hpp"
using namespace Adept;
#include <GameOS\GameOS.hpp>



//**************************************************
namespace MSRSpectator
{
	class CSpectatorStateEngine
	{
	public:
		CSpectatorStateEngine();                     // ctor
		~CSpectatorStateEngine();                    // dtor
		static void DeleteInstance(CSpectatorStateEngine* p); // will call delete
		void InitStateEngine(double delay);          // clears all states for new run of game
		void DumpData() const;                       // output stored object data
		bool SpectatorExecute();                     // main state engine execution tests
		void UpdateOldState();                       // stores current state as previous if state changes
		int GetCurState() const;                     // returns the current state
		bool SetLeader(Replicator* rep);             // stores the currents points leader entity Replicator
		                                             // returns true is new leader set
		void SetAttack(Replicator* inflicting, Replicator* victim);  // sets who's attacking who

		bool HasHero(Replicator** rep) const;        // returns true if m_entityA exists, sets rep to m_entityA
		bool HeroHasEngaged(Replicator** rep) const; // returns true if m_entityB exists, sets rep to m_entityB
		bool HasThirdParty(Replicator** rep) const;  // returns true if m_entityC exists, sets rep to m_entityC
		bool HasInflicting(Replicator** rep) const;  // returns the current inflicting party
		bool fInDyingSequence();                     // returns true if m_curState = DYING
		void SignalReSpawning(Mech* curSpawn);       // sets m_fIsDying to false when Mech request respawn 
		bool GetIsReSpawning() const;                // returns true if m_fIsDying is false
		void GetCurReSpawn(Mech** aMech);            // returns most recently respawned mech
		void ClearReSpawn();                         // sets m_fIsResurrecting false
		bool fTimeEnoughForNewShot();                // retruns true if m_shotTransTimer is expired, resets timer
		void UpdateShotTimer();                      // resets shot timer
		void InitDeathDelayTimer();                  // initializes death sequence camera delay till transition timer
		void InitDeathTransTimer();                  // intializes death sequence camera transition duration timer
		void ExpireDeathTimer();                     // expires death sequence timer
		double GetDeathTransTimeRemaining();         // returns time remaining in death camera transition timer
		double GetDeathDelayTimeRemaining();         // returns time remaining in death camera transition delay timer
		
		static CSpectatorStateEngine* GetInstance()  // required to support MW4's global pointer manager
		{
			return reinterpret_cast<CSpectatorStateEngine*>( GlobalPointers::GetGlobalPointer(SpectatorStateEnginePointerIndex));
		};

		void TestInstance(void) const;   // required to support MW4'S Check_Object()

		// external data retrieval (using Options.INI in MW4 directory)
		void LoadOptionsINI(NotationFile* optionsINI);
		void LoadINIData(const char* szData, int targetMember );
		const char* GetStringINIData(int dataMember) const;
		const float GetFloatINIData(int dataMember) const;
		const int GetIntINIData(int dataMember) const;

		Replicator* GetEntityA() const;              // returns current entity A replicator
		Replicator* GetEntityKiller() const;         // returns current entity killer replicator
		bool fIsSamePairing(Replicator* hero, Replicator* enemy);  // true if replicators are sames as last state cycle
		bool CSpectatorStateEngine::GetPrevHero(Replicator** prevHero) const;  // returns hero replicator of previous conflict
		bool CSpectatorStateEngine::GetPrevEnemy(Replicator** prevEnemy) const;  // returns enemy replicator of previous conflict

		// data
		enum {                     // exposed constants for our states
			STATE_ERR = -1,
			UNINITIALIZED = 0,
			DYING,
			RESET,
			SOLE,
			DUO,
			MULTI
		};

		// INI data fields.  Used to import camera data externally to quickly adjust cameras
		// Constants for identifying data fields to populate in INI reads
		enum {
			DATA_TEST,
			HUD_NAME_DISPLAY,
			HUD_CHAT_DISPLAY,
			OVER_SHOULDER_HERO_OFFSET_X,
			OVER_SHOULDER_HERO_OFFSET_Y,
			OVER_SHOULDER_HERO_OFFSET_Z,
			OVER_SHOULDER_ENEMY_OFFSET_X,
			OVER_SHOULDER_ENEMY_OFFSET_Y,
			OVER_SHOULDER_ENEMY_OFFSET_Z,
			SIDE_SHOT_DELTA_X,
			SIDE_SHOT_DELTA_Y,
			SIDE_SHOT_HEAD_Y,
			FRTSHOT_HEAD_Y,
			FRTSHOT_CAM_Y,
			FRTSHOT_DIST,
			FIXED_TRACK_X,
			FIXED_TRACK_Y,
			FIXED_TRACK_Z,
			DEATH_SEQUENCE_X,
			DEATH_SEQUENCE_Y,
			DEATH_SEQUENCE_Z,
			DEATH_ANIM_DELAY,
			DEATH_ANIM_DUR

		};             

	private:
		int m_curState;            // our current engine state
		int m_prevState;           // state prior to current state

	#if 0   // test values for quickly running FSM validation tests
		enum 
		{	
			IDLE_TIMER_DUR = 1,    // seconds duration for idle timer
			MULTI_TIMER_DUR = 2,   // seconds duration for multi timer
			STALL_TIMER_DUR = 1,   // seconds duration to stall between re-entering a multi state
			DEATH_TIMER_DUR = 2    // seconds duration for death sequence
		}; 
	#else   // real world FSM state timer values
		enum 
		{	
			IDLE_TIMER_DUR = 20,   // seconds duration for idle timer
			MULTI_TIMER_DUR = 4,   // seconds duration for multi timer
			STALL_TIMER_DUR = 2,   // seconds duration to stall between re-entering a multi state
			DEATH_TIMER_DUR = 4    // seconds duration for death sequence
		}; 
		
	#endif

		Replicator* m_entityA;	           // current center of focus combatant
		Replicator* m_entityB;             // current focust of conflict for A
		Replicator* m_entityC;             // current third party conflict for A
		Replicator* m_entityPointLeader;   // current highest point leader, used in RESET state
		Replicator* m_entityTargeted;      // A's currently fired upon enemy, NULL if not close
		Replicator* m_entityInflicting;    // enemy inflicting damage on A, NULL if non
		Replicator* m_entityKiller;        // enemy who just kille A, will be next A soon
		Replicator* m_entityCurHero;       // hero last time through camera updates
		Replicator* m_entityCurEnemy;      // enemy last time through camera updates
		Replicator* m_entityPrevHero;      // hero prior to current previous hero
		Replicator* m_entityPrevEnemy;     // enemy prior to current previous enemy
		Mech* m_curMechReSpawned;          // most recent respawning mech
		bool m_fIsDisabled;                // true if player is overheated, etc
		bool m_fIsDying;                   // true if player is in death sequence
		bool m_fIsResurrecting;            // true if mech has generated a respawn request to the game
		bool m_fEnemyDying;                // true if enemy is in death sequence
		CSpectatorTimer m_idleTimer;       // timer object used to measure inactivity of A
		CSpectatorTimer m_multiTimer;      // timer object used to measure third party engagement
		CSpectatorTimer m_stallTimer;      // timer object used to put space between times of re-entering multi states
		CSpectatorTimer m_deathTimer;      // timer object used to hold final camera during hero death sequence
		CSpectatorTimer m_shotTransTimer;  // timer object used to pace shot changes
		CSpectatorTimer m_watchBDieTimer;  // timer object used to delay looking away from killed enemy
		CSpectatorTimer m_targetedTimer;   // timer object used to delay between aquiring enemies, keeps camera from jumping too much
		CSpectatorTimer m_deathTransDelayTimer;  // timer object used to delay death camera trans start
		CSpectatorTimer m_deathTransTimer;       // timer object used to track death camera trans progress
		CSpectatorTimer m_testTimer;       // debug test timer

		char* m_dataTest;

		// interface overides
		int m_allowHudNameDisplay;
		int m_allowHudChatDisplay;

		// point data for camera adjustments, loaded from options.ini
		float m_overShoulderHeroOffset_x;
		float m_overShoulderHeroOffset_y;
		float m_overShoulderHeroOffset_z;
		float m_overShoulderEnemyOffset_x;
		float m_overShoulderEnemyOffset_y;
		float m_overShoulderEnemyOffset_z;
		float m_sideShotDelta_X;
		float m_sideShotDelta_Y;
		float m_sideShotHead_Y;
		float m_FrtShot_HeadY;
		float m_FrtShot_CamY;
		float m_FrtShot_Dist;
		float m_FixedTrack_X;
		float m_FixedTrack_Y;
		float m_FixedTrack_Z;
		float m_DeathSeq_X;
		float m_DeathSeq_Y;
		float m_DeathSeq_Z;
		float m_DeathAnimDelay;
		float m_DeathAnimDur;


	// private methods
		void GetCurGameData();           // gathers game data for combatant evaluations
		int ResetSpectator();            // clears states back to choose new A player
		bool A_DisabledStateChange();    // handles disabled player conditions, returns true if state conditions valid
		bool A_DyingStateChange();       // handles dying player conditions, returns true if state conditions valid
		bool A_ShootingStateChange();    // handles A shooting-at conditions, returns true if state conditions valid
			
		char bigThing[256];             // MW4 memory allocation doesn't like small things
	};
}
#endif // !defined(MSR_SPECTATOR_STATE_ENGINE_)


