//===========================================================================// // 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 #pragma warning(pop) #include "AI_FireParamPackage.hpp" #include "NetWeapon.hpp" #include "AI_SquadOrders.hpp" #include "torso.hpp" namespace std { template 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 *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 *message); protected: static const MessageEntry MessageEntries[]; typedef std::vector 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 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 m_LastAttackOrderPosition; Stuff::Auto_Ptr m_LastMoveOrderPosition; bool m_WaitingForHeatToReachMinSkill; std::vector 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 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 m_CanSeeResults; Stuff::Auto_Ptr 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 m_CachedTorsoRayCastFailures; std::vector 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 m_FireSourceCache; Stuff::Scalar m_CurrentVulnerableComponent; PatienceMonitor m_FiringAttemptMonitor; PatienceMonitor m_OpportunityFireMonitor; Adept::ObjectID m_CachedNearest[2]; Stuff::Time m_CachedNearestTime[2]; std::vector 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& 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& 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& 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& 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& 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& 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::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