//===========================================================================//
// File:	CombatAI.hpp																	     //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
//	09/21/99  PDT	Created File											//
//					Question: why is this even here when we have SourceSafe? ... //
//---------------------------------------------------------------------------//
// Copyright (C) 1999, Microsoft										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once
#ifndef COMBATAI_HPP
#define COMBATAI_HPP

#include "MoverAI.hpp"
#include "AI_Tactics.hpp"
#include "AI_CombatTacticInterface.hpp"
#include "aiutils.hpp"
#include "AI_Weapons.hpp"
#include "Group.hpp"
#include "AI_SearchLight.hpp"
#pragma warning(push)
#include <stlport\list>
#pragma warning(pop)
#include "AI_FireParamPackage.hpp"
#include "NetWeapon.hpp"
#include "AI_SquadOrders.hpp"
#include "torso.hpp"


namespace std
{
	template <class T> class vector;
};

namespace MW4AI
{
	namespace FireStyles
	{
		class FireStyle;
	};

	class FireParamPackage;
	extern HGOSHEAP g_CombatAIHeap;
};

namespace Adept
{
	class DamageObject;
};

namespace MechWarrior4
{
	class MWObject;

	typedef MoverAI__CreateMessage			CombatAI__CreateMessage;

	//##########################################################################
	//###########################   CombatAI    ################################
	//##########################################################################

	class CombatAI
		: public MoverAI
	{
		typedef MoverAI inherited;

		friend class MW4AI::CombatTacticInterface;

	public:
		static void InitializeClass();
		static void TerminateClass();

		static ClassData *DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tactics
	//

		enum AttackState
		{
			ATTACKING				= true,
			NOT_ATTACKING			= false
		};
		inline AttackState GetAttackState() const;

		inline MW4AI::TacticInterface& GetTacticInterface();

		MWObject* GetNearest(bool fMustBeEnemy = false); // TODO: make this an enum or something  ...

		inline Stuff::Point3D GetMoveDest() const;

		bool ReactToCollision(Stuff::DynamicArrayOf<CollisionData> *collisions,bool& shoulddamage);

		bool PointIsInBadNeighborhood(const Stuff::Point3D& point) const;

		Stuff::Scalar GetCombatRadiusForRange(Stuff::Scalar percentile_range);

		bool MovedWithin(Stuff::Scalar duration) const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		typedef CombatAI__CreateMessage					CreateMessage;

		void TrackToPoint(const Stuff::Point3D& point);
		void TurnToPoint(const Stuff::Point3D& point, bool must_be_torso_twisted = true);
		void PitchToPoint(const Stuff::Point3D& point);

		inline Stuff::Scalar GetTimeTargetedByFriendly() const;

		virtual void Save (MemoryStream *stream);
		virtual void Load (MemoryStream *stream);

		virtual void NotifyRespawned();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static CombatAI* Make(CreateMessage *message,ReplicatorID *base_id);	// FYI, this really should return an Auto_Ptr<>! -- PT


		CombatAI(ClassData *class_data,
				 CreateMessage *message,
				 ReplicatorID *base_id,
				 ElementRenderer::Element *element);

		~CombatAI();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message Support
	//
	public:

		enum
		{
			DebugTextMessageID = MechWarrior4::MoverAI::NextMessageID,
			NextMessageID
		};

		void DebugTextMessageHandler(Adept::ReceiverDataMessageOf<int> *message);

		protected:
			static const MessageEntry MessageEntries[];

		typedef std::vector<MWObject*> secondary_target_list;

		virtual bool CanMove() const;
		bool MoveRequestPending();
		bool CanTurn();
		bool CanTrack();

	private:
		class PatienceMonitor
		{
		  public:
			PatienceMonitor(int maximum);

			bool Check();
			void Notify(bool success);

		  private:
			const int m_Maximum;
			int m_Patience;
			int m_Frustration;
		};



	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
		Stuff::Scalar m_LastTimeMoved;

	protected:
		Stuff::Auto_Ptr<MW4AI::Tactics::Tactic> m_Tactic;

		Point3D m_LastPos;

		Point3D m_LastMoveDest;

		Point3D m_LastAimPoint;

		MW4AI::CombatTacticInterface m_Interface;

		MW4AI::FireData::HIT_RESULT m_HitResult;

		Stuff::Scalar m_DistanceFromTargetSquared;

		bool m_OverridingMovement;

		Stuff::Scalar m_AttackThrottle;

		Stuff::Scalar m_LastFireTime;

		Stuff::Scalar m_MinFiringDelay;
		Stuff::Scalar m_MaxFiringDelay;

		Stuff::Scalar m_LastTimeProjectileShotAtMe;
		Stuff::Point3D m_LastProjectileOrigin;

		Stuff::Scalar m_ThrottleOverrideStopTime;

		bool m_HoldingFire;
		bool m_InternalArmorBreached;

		bool m_LeftArmExists;
		bool m_RightArmExists;
		bool m_ForceDestinationRecalc;
		
		char m_NumArmsBlownOff;
		char m_NumLegsBlownOff;

		Stuff::Scalar m_LastUnableToFireTime;

		Stuff::Time m_LastFrameTime;
		Stuff::Time m_ApproximateTimeBetweenFrames;

		Stuff::Scalar m_LastFriendlyFireTime;
		Stuff::Scalar m_FriendlyFireDelay;

		Stuff::Scalar m_LastTimeTargeted;
		Stuff::Scalar m_TimeBeingTargeted;
		int			  m_LastTargetedAlignment;

		Stuff::Scalar m_LastTimeRammedTarget;

		Stuff::Scalar m_LastTimeJumped;
		Stuff::Scalar m_JumpDuration;

		bool m_PerformedFirstUpdate;

		Stuff::Scalar m_SquadTargetingRadius;

		Stuff::Point3D m_ExplicitFirePoint;
		int m_ExplicitFireStretch;

		Stuff::Auto_Ptr<Stuff::LinearMatrix4D> m_LastAttackOrderPosition;
		Stuff::Auto_Ptr<Stuff::LinearMatrix4D> m_LastMoveOrderPosition;

		bool m_WaitingForHeatToReachMinSkill;

		std::vector<MW4AI::Tactics::TacticID> m_MostRecentTactics;

		MW4AI::SearchLightController m_SearchLightController;

		enum LookState
		{
			LOOK_LEFT,
			LOOK_RIGHT,
			LOOK_CENTER,
			LOOK_BACK
//			,LOOK_UP,
//			,LOOK_DOWN
		};

		LookState m_LookState;
		Stuff::Scalar m_LastLookTime;
		Stuff::Scalar m_LastTimeLookChanged;

		std::vector<Stuff::Point3D> m_BlockedMovePoints;

		Stuff::Scalar m_AttackRadiusMultiplier;

		Stuff::Point3D m_LastOffsetToMiss;

		Stuff::Scalar m_MissOffsetStartTime;

		Stuff::Scalar m_Last_Till_Value;

		struct CanSeeResult
		{
			MW4AI::FireData::HIT_RESULT m_Result;
			Adept::ObjectID m_Entity;
			Stuff::Scalar m_Angle;
			Stuff::Scalar m_Time;
		};

		std::vector<CanSeeResult> m_CanSeeResults;

		Stuff::Auto_Ptr<MW4AI::SquadOrders> m_SquadOrders;

		#ifdef LAB_ONLY
		bool m_LastFireRejected;
		#endif

		Adept::ObjectID m_CheapShotTarget;
		bool m_CheapShotShouldHit;
		bool m_CheapShotShouldSpendAmmo;

		bool m_PerWeaponRayCasting;

		struct CachedTorsoRayCastFailure
		{
			Weapon* weapon;
			Stuff::Scalar time;
		};

		std::list<CachedTorsoRayCastFailure> m_CachedTorsoRayCastFailures;

		std::vector<Stuff::Scalar> m_MostRecentNoPathWarnings;

		Stuff::Scalar m_LastTimeSwitchedTargets;

		bool m_AutoTargetingEnabled;

		Stuff::Scalar m_MinSpeed;

		Stuff::Scalar m_GoalPitch;
		Stuff::Scalar m_GoalYaw;

		secondary_target_list m_SecondaryTargets;

		Stuff::Time m_LastAttackIntervalRefresh;

		Stuff::Scalar m_MinAttackInterval;
		Stuff::Scalar m_MaxAttackInterval;

		MW4AI::FireStyles::MaximumFire m_MaximumFire;
		MW4AI::FireStyles::OpportunityFire m_OpportunityFire;

		struct CachedFireSource
		{
			MW4AI::FireSource fire_source;
			Adept::ObjectID object_id;
			Stuff::Time last_update;
		};

		std::vector<CachedFireSource> m_FireSourceCache;

		Stuff::Scalar m_CurrentVulnerableComponent;

		PatienceMonitor m_FiringAttemptMonitor;
		PatienceMonitor m_OpportunityFireMonitor;

		Adept::ObjectID m_CachedNearest[2];
		Stuff::Time m_CachedNearestTime[2];

		std::vector<Weapon*> m_SavedWeapons;

		Stuff::Time m_MoveRequestFinishedTime;
		Stuff::Scalar m_LastAttackOrderDamageRating;

		bool m_ShutDownDueToHeat;

		bool m_IgnoreFog;

	public:
		
		bool OverridingMovement (void) const
		{ return m_OverridingMovement; }


		virtual void Shutdown() { inherited::Shutdown(); }
		virtual void Startup() { inherited::Startup(); }

		inline void EnablePerWeaponRayCasting(bool enable);

		inline MW4AI::SearchLightController& GetSearchLightController();

		void PreCollisionExecute(Stuff::Time till);
		void PostCollisionExecute(Time till);

		inline Stuff::Scalar GetLastFiredTime() const;

		inline MWObject& GetSelf();
		inline const MWObject& GetSelf() const;

		inline Vehicle* GetSelf_AsVehicle();
		inline const Vehicle* GetSelf_AsVehicle() const;

		inline int GetNumArmsBlownOff() const;
		inline int GetNumLegsBlownOff() const;

		inline bool ShouldForceDestinationRecalc() const;
		inline void ForceDestinationRecalc();

		bool CanSee(MWObject& entity, Stuff::Scalar cheat_angle = Stuff::Pi_Over_4);

		inline bool ShouldHoldFireToAvoidFriendlyFire() const;

		inline Stuff::Scalar GetLastTimeRammedTarget() const;
		inline Stuff::Scalar GetLastTimeJumped() const;

		inline Stuff::Scalar GetSquadTargetingRadius() const;
		inline void SetSquadTargetingRadius(Stuff::Scalar radius);

		bool GetEscapeRegionFocusIfAvailable(Stuff::Point3D& focus) const;

		inline void SetSquadOrders(Stuff::Auto_Ptr<MW4AI::SquadOrders>& orders);
		inline MW4AI::SquadOrders* GetSquadOrders();

		inline bool GetAutoTargeting() const;
		inline void SetAutoTargeting(bool enabled);

		inline bool GetIgnoreFog() const;
		inline void SetIgnoreFog(bool ignore);

		void FacePointOrLookOut(const Stuff::Point3D& point);

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Order Support
		//

		void OrderAttack(bool fOverrideCurrentMove = true);											// OrderAttack(): attack current target with "best" tactic, TBD by mech itself
		void OrderAttackTactic(MW4AI::Tactics::TacticID tactic, bool fOverrideCurrentMove = true, bool is_explicit = true);	// OrderAttackTactic(): attack current target with given tactic
		void OrderShootPoint(const Stuff::Point3D& point, int stretch = 0);
		void OrderStopAttacking();						// OrderStopAttacking(): stop attacking the current target
		void OrderJump();
		void OrderJump(Stuff::Scalar duration);
		void OrderStopJumping();

		void TrackOrTurnToPoint(const Point3D& point);

		void Reset(bool reset_movement = true);

		inline MW4AI::Tactics::TacticID GetCurrentTactic() const;
		inline bool TacticIsFinished() const;

//		void 	orderMoveLookOut (void);

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Debug Stuff
		//
		void AddStatsToString(std::string& s);
		void Info (void (*printCallback)(char* s));

		void GetDirectPath(std::vector<Stuff::Point3D>& points);

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Other Stuff
		//

		inline Stuff::Scalar GetAttackThrottle() const;
		inline void SetAttackThrottle(Stuff::Scalar throttle);

		inline Stuff::Scalar GetBaseChanceToHit() const;

		inline void SetFiringDelay(Stuff::Scalar min, Stuff::Scalar max);

		void ThrottleOverride(Stuff::Scalar duration, bool force = false);

		void EnsureNotTargeting(Adept::ObjectID object);

		Stuff::Scalar MaxVehicleSpeed();

		void MoveToPoint(const Stuff::Point3D& point);
		void FloatToPoint(const Stuff::Point3D& point);

		bool PointIsValid(const Point3D& point, bool ignore_mission_bounds = false, bool ignore_squads = false) const;

		void NotifyProjectileApproaching(const Stuff::Point3D& origin);
		void NotifyShot(ObjectID who, bool fCanBeRecursive = true);
		void NotifyShotFired(const Adept::Entity::CollisionQuery& query, MWObject& shooter);
		void NotifyLastShotWasFriendlyFire(Adept::Entity& who_i_hit);
		void NotifyInternalHit();
		void NotifyComponentDestroyed(int zone);
		void NotifyShutdown();
		void NotifyAlignmentChanged();
		void NotifyInTargetingReticule(MWObject& who);
		void NotifyHeatShutdownImminent();
		void NotifyFailedPilotingRoll();
		void NotifyFriendlyFire(Adept::Entity& who_shot_me);

		virtual void ContinuousFlyBy(const Stuff::Point3D& loc);

		virtual bool GetExtendedSensorData(std::vector<MWObject*>& sensor_data_list);
		virtual Stuff::Scalar GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const;

		inline bool GetHoldingFire() const;
		inline void SetHoldingFire(bool hold_fire);

		inline bool Attacking() const;

		bool GetUnableToFireDuration(Stuff::Scalar within) const;

		inline Stuff::Scalar GetAttackRadiusMultiplier() const;
		void SetAttackRadiusMultiplier(Stuff::Scalar multiplier);

		Stuff::Scalar GetMoodRadiusMultiplier() const;

		void CenterTorso();
		void SurrenderPose();

		inline Stuff::Scalar GetCurrentVulnerableComponent() const;

		inline void Execute_TurnToPoint(const Stuff::Point3D& point);

		bool MoveDone() const;

		void Crouch();
		bool Crouching();

		bool RecentPathsFailed() const;

		MWObject* FindBestAutoTarget();

		void SetMinSpeed(Stuff::Scalar min_speed);

		void SetGoalPitch(Stuff::Scalar pitch);
		void SetGoalYaw(Stuff::Scalar yaw);

	protected:
		bool GetIgnoringFriendlyFire() const;

		void Update(Stuff::Time till);

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Command Support
		//

	public:
		enum
		{
			ATTACK_HIGHID = MoverAI::NextHighCommandID,
			STOP_ATTACKING_HIGHID,
			NextHighCommandID
		};

		enum
		{
			NOT_IMPLEMENTED_LOWID = MoverAI::NextLowCommandID,
			NextLowCommandID
		};

		struct AimPoint
		{
			AimPoint() {};
			AimPoint(const Stuff::Point3D& _aim_point,
					 Adept::Entity* _entity)
				: aim_point(_aim_point)
				, entity(_entity)
			{
			}

			Stuff::Point3D aim_point;
			Adept::Entity* entity;
		};

		inline Stuff::Scalar GetTimeTargetedByEnemy() const;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Command Implementation
		//

	private:
		MW4AI::Tactics::TacticID SelectBestTactic() const;

		inline MWObject& GetTarget();

		inline Vehicle* GetTarget_AsVehicle();

		MWObject* GetFiringTarget() const;

//		const MWMover& GetBestTargetComponent() const;

		void StartAttacking(MW4AI::Tactics::TacticID tactic, bool fOverrideCurrentMove = true, bool is_explicit = false);
		void StopAttacking();

		inline void KillTracking();

		inline void UpdateFrameTiming();
		void UpdateFriendlyFireTiming();
		void UpdateSquad();
		void UpdateMoving();
		void UpdateThrottleOverride();
		void UpdateAttacking();
		void UpdateBeingTargeted();
		void UpdateWaitingForHeatToReachZero();
		void UpdateLookState();
		void UpdateJumping();
		void UpdateAutoTargeting();
		void UpdateGoalPitchAndYaw();
		void UpdateNoPathWarnings();
		void UpdateCurrentVulnerableComponent();

		void AttackExplicitFirePoint();

		void OffsetTargetQuery(Entity__CollisionQuery& q) const;

		void Execute_TrackToPoint(const Stuff::Point3D& point);

		void MoveToPoint(const Stuff::Point3D& point, bool move_forward, bool dont_use_throttle = false, MWObject* ram_target = 0);

		void StopMoving();
		void SetSpeed(Stuff::Scalar speed);
		Stuff::Scalar RecommendedCurrentSpeed();

		void ModifyMood(Stuff::Scalar multiplier);

		void ModifyChanceToHit(Stuff::Scalar& chance_to_hit, MWObject& target, const Stuff::LinearMatrix4D& my_matrix, Stuff::Scalar distance_from_target);

		Stuff::Scalar ApproximateDistanceToTarget();

		void TryToFire(MW4AI::FireStyles::FireStyleID style_id);
		bool TryToFireAt(MW4AI::FireStyles::FireStyle& style, MWObject& who, bool should_hit);
		bool MightBeAbleToFireAt(MW4AI::FireStyles::FireStyle& style, MWObject& who);
		bool TryToHit(MWObject& who, MW4AI::FireStyles::FireStyle& style);
		bool TryToHitAtPoints(MWObject& who, MW4AI::FireStyles::FireStyle& style, const std::list<AimPoint>& aim_points, bool can_hit_dead_components = false);
		bool TryToMiss(MWObject& who, MW4AI::FireStyles::FireStyle& style);
		inline Point3D GetFireSource();
		bool ShotShouldHit(MWObject& who);
		Stuff::Point3D GetNewAimPoint_ToMiss(MWObject& who, const Stuff::Point3D& self_pos);
		bool Fire(MWObject& who, Adept::Entity* component, MW4AI::FireSource fire_source, const Stuff::LinearMatrix4D& matrix, const Stuff::Point3D& target_point, MW4AI::FireStyles::FireStyle& style, bool should_hit);
		void FireAtAimPoint(MW4AI::FireStyles::FireStyle& style,
							MechWarrior4::MWObject* who,
							Adept::Entity* component,
							MW4AI::FireSource fire_source,
							const Stuff::LinearMatrix4D& source_matrix,
							Adept::Entity* who_to_hit,
							Vehicle* vehicle_shooting_at,
							bool can_spend_ammo);

		Adept::DamageObject* PickComponent(MWObject& who, const MW4AI::component_vector& components);

		bool IsMovingQuickly(MWObject& who);

		void InitializeSecondaryTargets(secondary_target_list& secondary_targets);
		secondary_target_list::iterator SelectSecondaryTarget(secondary_target_list& secondary_targets);

		inline bool CanOpportunityFire(MW4AI::FireStyles::FireStyle& style) const;

		inline MWMover* GetEyeSitePointer();

		inline void ResetTorso();

		Stuff::Scalar CalcTorsoTwistDemand(const Point3D& point, MechWarrior4::Torso& torso, bool for_multi_torso);

		Stuff::Scalar GetMaxFireCheatAngle();
		bool IsLaserTurret();

		bool SuicideIsOK() const;

		void SetLookState(LookState state);
		void SetLookState(const MW4AI::FireStyles::FireStyle& fire_style);

		void SuggestPointWasNotAGoodDestination(const Stuff::Point3D& dest);

		MW4AI::FireSource GetBestFireSource(MechWarrior4::MWObject& who);
		MW4AI::FireSource GetBestFireSource(const Stuff::Point3D& target_point);
		Stuff::LinearMatrix4D GetFireSourceMatrix(MW4AI::FireSource fire_source);

		void GetAttackInterval(Stuff::Scalar& min, Stuff::Scalar& max);

		bool ShouldSpendAmmoAgainst(MWObject& who, MW4AI::FireStyles::FireStyle& style);

		void ThisIsAMethodToSetABreakpointInIfCurrentVehicle();

		Stuff::Scalar GetNormalizedCurrentHeat() const;

		bool LineMightHitFriendlyUnits(const Stuff::Line3D& line);

		bool LeftmostOrRightmostWeaponHitsSomethingElse(const MW4AI::FireParamPackage& params);

		void RefreshCanSeeResults();

		Stuff::Scalar GetComponentScore(int armor_component, int internal_component, Stuff::Scalar max_score, bool is_left);

		Stuff::Point3D GetLongTomPitchPoint();

		bool CanFireNARC();
		bool CanFireHeatGeneratingWeapons() const;

		void SetFallDampingEnabled(bool enabled);

		void CheapShot(MWObject& who, bool should_hit, bool should_spend_ammo);

		Stuff::Scalar GetModifiedMaxTorsoTwistSpeed(MechWarrior4::Torso& torso);

		void GetAimPoints(MWObject& who, std::list<AimPoint>& aim_points);

		void MultiTurretFire(MW4AI::FireStyles::FireStyle& style);

		MWObject* GetNearestEnemyToLine(Stuff::Line3D& line, const secondary_target_list& targets);

		void OpportunityFire(MW4AI::FireStyles::FireStyle& style);

	protected:
		void NotifyNoPath();

		virtual Stuff::Scalar GetMinSpeed() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void TestInstance() const;
	};




	inline void CombatAI::EnablePerWeaponRayCasting(bool enable)
	{
		m_PerWeaponRayCasting = enable;
	}

	inline void CombatAI::SetSquadOrders(Stuff::Auto_Ptr<MW4AI::SquadOrders>& orders)
	{
		m_SquadOrders = orders;
	}

	inline MW4AI::SquadOrders* CombatAI::GetSquadOrders()
	{
		return (m_SquadOrders.GetPointer());
	}

	inline bool CombatAI::TacticIsFinished() const
	{
		if (m_Tactic.GetPointer() == 0)
		{
			return (true);
		}

		return (m_Tactic->Finished());
	}

	inline MW4AI::Tactics::TacticID CombatAI::GetCurrentTactic() const
	{
		Verify(GetAttackState() == ATTACKING);

		return (m_Tactic->GetID());
	}

	inline Stuff::Scalar CombatAI::GetAttackRadiusMultiplier() const
	{
		if (m_AttackRadiusMultiplier != 0)
		{
			return (m_AttackRadiusMultiplier);
		}

		return (GetMoodRadiusMultiplier());
	}

	inline MW4AI::SearchLightController& CombatAI::GetSearchLightController()
	{
		return (m_SearchLightController);
	}

	inline Stuff::Point3D CombatAI::GetMoveDest() const
	{
		return (m_LastMoveDest);
	}

	inline Stuff::Scalar CombatAI::GetLastTimeRammedTarget() const
	{
		return (m_LastTimeRammedTarget);
	}

	inline Stuff::Scalar CombatAI::GetLastTimeJumped() const
	{
		return (m_LastTimeJumped);
	}

	inline Stuff::Scalar CombatAI::GetTimeTargetedByEnemy() const
	{
		if (m_LastTargetedAlignment != GetSelf().GetAlignment())
		{
			return (m_TimeBeingTargeted);
		}

		return (0);
	}

	inline Stuff::Scalar CombatAI::GetTimeTargetedByFriendly() const
	{
		if (m_LastTargetedAlignment == GetSelf().GetAlignment())
		{
			return (m_TimeBeingTargeted);
		}

		return (0);
	}

	inline Stuff::Scalar CombatAI::GetSquadTargetingRadius() const
	{
		return (m_SquadTargetingRadius);
	}

	inline void CombatAI::SetSquadTargetingRadius(Stuff::Scalar radius)
	{
		m_SquadTargetingRadius = radius;
	}

	inline MWMover* CombatAI::GetEyeSitePointer()
	{
		return (GetSelf().eyeSitePointer.GetCurrent());
	}

	inline bool CombatAI::ShouldForceDestinationRecalc() const
	{
		return (m_ForceDestinationRecalc);
	}

	inline void CombatAI::ForceDestinationRecalc()
	{
		m_ForceDestinationRecalc = true;
	}

	inline MWObject& CombatAI::GetSelf()
	{
		Check_Pointer(getEntity());
		Verify(getEntity()->IsDerivedFrom(MWObject::DefaultData));

		return (*(Cast_Object(MWObject*,getEntity())));
	}

	inline const MWObject& CombatAI::GetSelf() const
	{
		Check_Pointer(getEntity());
		Verify(getEntity()->IsDerivedFrom(MWObject::DefaultData));

		return (*(Cast_Object(MWObject*,getEntity())));
	}

	inline MWObject& CombatAI::GetTarget()
	{
		Verify(Target() != 0);
		Verify(Target()->IsDerivedFrom(MWObject::DefaultData));

		return (*(Cast_Object(MWObject*,Target())));
	}

	inline Vehicle* CombatAI::GetSelf_AsVehicle()
	{
		MWObject& self = GetSelf();

		if (self.IsDerivedFrom(Vehicle::DefaultData))
		{
			return (Cast_Object(Vehicle*,&self));
		}

		return (0);
	}

	inline const Vehicle* CombatAI::GetSelf_AsVehicle() const
	{
		const MWObject& self = GetSelf();

		if (self.IsDerivedFrom(Vehicle::DefaultData))
		{
			return (Cast_Object(const Vehicle*,&self));
		}

		return (0);
	}

	inline Vehicle* CombatAI::GetTarget_AsVehicle()
	{
		MWObject& target = GetTarget();

		if (target.IsDerivedFrom(Vehicle::DefaultData))
		{
			return (Cast_Object(Vehicle*,&target));
		}

		return (0);
	}

	inline void CombatAI::Execute_TurnToPoint(const Point3D& point)
	{
		MW4AI::AutoHeap local_heap(MW4AI::g_CombatAIHeap);

		MW4AI::CommandEntry* turn = CreateTurnToCommand(point,false);
		Check_Pointer(turn);
		ExecuteCommand(turn);
	}

	inline void CombatAI::KillTracking()
	{
		MW4AI::AutoHeap local_heap(MW4AI::g_CombatAIHeap);

		if (CanMove() == false)
		{
			return;
		}

		MW4AI::CommandEntry* kill_tracking = CreateKillTrackCommand();
		Check_Pointer(kill_tracking);
		ExecuteCommand(kill_tracking);
	}

	inline void CombatAI::ResetTorso()
	{
		MW4AI::AutoHeap local_heap(MW4AI::g_CombatAIHeap);

		{for (std::vector<Torso*>::const_iterator i = GetSelf().GetTorsos().begin();
			  i != GetSelf().GetTorsos().end();
			  ++i)
		{
			(*i)->yawDemand = 0;
			(*i)->pitchDemand = 0;
		}}
	}

	inline Point3D CombatAI::GetFireSource()
	{
		if (GetEyeSitePointer() != 0)
		{
			return ((Point3D)GetEyeSitePointer()->GetLocalToWorld());
		}

		return ((Point3D)GetSelf().GetLocalToWorld());
	}

	inline Stuff::Scalar CombatAI::GetAttackThrottle() const
	{
		return (m_AttackThrottle);
	}

	inline void CombatAI::SetAttackThrottle(Stuff::Scalar throttle)
	{
		Verify(throttle <= 100);
		Verify(throttle >= 0);

		m_AttackThrottle = throttle;
	}

	inline Stuff::Scalar CombatAI::GetBaseChanceToHit() const
	{
		return (GunnerySkill() * 0.01f);
	}

	inline void CombatAI::SetFiringDelay(Stuff::Scalar min, Stuff::Scalar max)
	{
		Verify(min >= 0);
		Verify(max >= 0);
		Verify(min <= max);

		m_MinFiringDelay = min;
		m_MaxFiringDelay = max;
	}

	inline bool CombatAI::ShouldHoldFireToAvoidFriendlyFire() const
	{
		if (m_FriendlyFireDelay == 0)
		{
			return (false);
		}

		return (gos_GetElapsedTime() <= m_LastFriendlyFireTime + m_FriendlyFireDelay);
	}

	inline MW4AI::TacticInterface& CombatAI::GetTacticInterface()
	{
		return (m_Interface);
	}

	inline Stuff::Scalar CombatAI::GetLastFiredTime() const
	{
		return (m_LastFireTime);
	}

	inline bool CombatAI::GetHoldingFire() const
	{
		return (m_HoldingFire);
	}

	inline void CombatAI::SetHoldingFire(bool hold_fire)
	{
		m_HoldingFire = hold_fire;
	}

	inline int CombatAI::GetNumArmsBlownOff() const
	{
		return (m_NumArmsBlownOff);
	}

	inline int CombatAI::GetNumLegsBlownOff() const
	{
		return (m_NumLegsBlownOff);
	}

	inline bool CombatAI::Attacking() const
	{
		return (GetAttackState() == ATTACKING);
	}

	inline CombatAI::AttackState CombatAI::GetAttackState() const
	{
		if (m_Tactic.GetPointer() == 0)
		{
			return (NOT_ATTACKING);
		}

		return (ATTACKING);
	}

	inline void CombatAI::UpdateFrameTiming()
	{
		m_ApproximateTimeBetweenFrames = gos_GetElapsedTime() - m_LastFrameTime;

		m_LastFrameTime = gos_GetElapsedTime();
	}

	inline bool CombatAI::CanOpportunityFire(MW4AI::FireStyles::FireStyle& style) const
	{
		if (style.CanAlwaysFireAtSecondaryTargets() == true)
		{
			return (true);
		}

		Stuff::Scalar elite((Stuff::Scalar)EliteSkill());

		if ((elite >= MW4AI::UserConstants::Instance()->Get(MW4AI::UserConstants::min_opportunity_fire)) &&
			(elite <= MW4AI::UserConstants::Instance()->Get(MW4AI::UserConstants::max_opportunity_fire)))
		{
			return (true);
		}

		return (false);
	}

	inline bool CombatAI::RecentPathsFailed() const
	{
		return (m_MostRecentNoPathWarnings.size() > 1);
	}

	inline bool CombatAI::GetAutoTargeting() const
	{
		return (m_AutoTargetingEnabled);
	}

	inline void CombatAI::SetAutoTargeting(bool enabled)
	{
		m_AutoTargetingEnabled = enabled;
	}

	inline Stuff::Scalar CombatAI::GetCurrentVulnerableComponent() const
	{
		return (m_CurrentVulnerableComponent);
	}

	inline void CombatAI::SetIgnoreFog(bool ignore)
	{
		m_IgnoreFog = ignore;
	}

	inline bool CombatAI::GetIgnoreFog() const
	{
		return (m_IgnoreFog);
	}
}



#endif // COMBATAI_HPP