#include "MW4Headers.hpp" #include "AI_CombatTacticInterface.hpp" #include "AI_Weapons.hpp" #include "Mech.hpp" #include "MWMission.hpp" #include "Airplane.hpp" #include "AI_FireStyle.hpp" #include "AI_Tactics.hpp" #include "Mech.hpp" #include "JumpJet.hpp" #include "AI_Groups.hpp" #include "AI_Damage.hpp" #include "ShooterAI.hpp" using namespace MW4AI; extern __int64 tCombatAITime_ShotWithin; bool CombatTacticInterface::g_DisableMovement = false; bool CombatTacticInterface::g_DisableFiring = false; const Stuff::Scalar min_move_reissuance_distance = 8.0f; CombatTacticInterface::CombatTacticInterface(MechWarrior4::CombatAI& combat_ai) : m_CombatAI(combat_ai) , m_LastMoveDestScore(0) { } void CombatTacticInterface::MoveTo(const Point3D& point, bool move_forward, bool throttle_override, MWObject* ram_target) { #ifdef LAB_ONLY if (ram_target == 0) { Verify(PointIsValid(point,true)); } if (g_DisableMovement == true) { Stop(); return; } #endif // TODO: move this somewhere else; also take move_forward and throttle_override into account if ((m_CombatAI.m_TimeNotMoving == 0) && (GetLengthSquared(m_CombatAI.m_LastMoveDest,point) < (min_move_reissuance_distance * min_move_reissuance_distance))) { return; } m_CombatAI.MoveToPoint(point,move_forward,throttle_override,ram_target); m_LastMoveDestScore = 0; } Stuff::Point3D CombatTacticInterface::GetAimPoint() const { return (m_CombatAI.m_LastAimPoint); } void CombatTacticInterface::TrackTo(const Stuff::Point3D& point) { m_CombatAI.TrackToPoint(point); } void CombatTacticInterface::TurnTo(const Stuff::Point3D& point, bool must_be_torso_twisted) { m_CombatAI.TurnToPoint(point,must_be_torso_twisted); } void CombatTacticInterface::PitchTo(const Stuff::Point3D& point) { m_CombatAI.PitchToPoint(point); } void CombatTacticInterface::Stop() { m_CombatAI.StopMoving(); m_LastMoveDestScore = 0; } void CombatTacticInterface::Fire(FireStyles::FireStyleID style_id) { #ifdef LAB_ONLY if (g_DisableFiring == true) { return; } #endif m_CombatAI.TryToFire(style_id); } bool CombatTacticInterface::HasPath() const { if (m_CombatAI.m_CurPath != 0) { return (true); } return (false); } bool CombatTacticInterface::Moving() const { return (m_CombatAI.m_TimeNotMoving == 0); } Stuff::Scalar CombatTacticInterface::WeaponRange(WR_WHO who, WR_QUALIFIER qualifier) const { MWObject* x = 0; if (who == TacticInterface::SELF) { x = &(m_CombatAI.GetSelf()); } else { x = &(m_CombatAI.GetTarget()); } if (qualifier == TacticInterface::MIN) { return (GetMinWeaponDistance(*x)); } return (GetMaxWeaponDistance(*x)); } bool CombatTacticInterface::PointIsValid(const Point3D& point, bool ignore_mission_bounds, bool ignore_squads) const { return (m_CombatAI.PointIsValid(point,ignore_mission_bounds,ignore_squads)); } MechWarrior4::MWObject& CombatTacticInterface::GetSelf() const { return (m_CombatAI.GetSelf()); } MechWarrior4::Vehicle* CombatTacticInterface::GetSelf_AsVehicle() const { return (m_CombatAI.GetSelf_AsVehicle()); } MechWarrior4::MWObject& CombatTacticInterface::GetTarget() const { return (m_CombatAI.GetTarget()); } MechWarrior4::Vehicle* CombatTacticInterface::GetTarget_AsVehicle() const { return (m_CombatAI.GetTarget_AsVehicle()); } FireData::HIT_RESULT CombatTacticInterface::GetLastHitResult() const { return (m_CombatAI.m_HitResult); } Stuff::Scalar CombatTacticInterface::GetDistanceFromTargetSquared() const { return (m_CombatAI.m_DistanceFromTargetSquared); } Moods::ID CombatTacticInterface::GetMood() const { int current_mood = (int)m_CombatAI.CurrentMood(); return ((Moods::ID)current_mood); } Stuff::Scalar CombatTacticInterface::GetDistanceFromDestinationSquared() const { if ((m_CombatAI.m_CurMove == 0) || (m_CombatAI.m_CurMove->Done() == true)) { return (0); } if (m_CombatAI.m_LastMoveDest.GetLengthSquared() == 0) { return (0); } Stuff::Vector3D delta; delta.Subtract((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(), m_CombatAI.m_LastMoveDest); return (delta.GetLengthSquared()); } bool CombatTacticInterface::GetLastMoveDest(Stuff::Point3D& dest, bool ignore_movement) const { if (ignore_movement == false) { if ((m_CombatAI.m_CurMove == 0) || (m_CombatAI.m_CurMove->Done() == true)) { return (false); } } dest = m_CombatAI.m_LastMoveDest; return (true); } void CombatTacticInterface::ClearMoveOrder() { m_CombatAI.ClearMoveOrder(); m_LastMoveDestScore = 0; } bool CombatTacticInterface::ProjectileApproaching(Stuff::Scalar interval) { const Stuff::Scalar min_reaction_delay = 0.2f; Verify(interval > min_reaction_delay); if ((m_CombatAI.m_LastTimeProjectileShotAtMe == 0) || (gos_GetElapsedTime() < m_CombatAI.m_LastTimeProjectileShotAtMe + min_reaction_delay)) { return (false); } return (gos_GetElapsedTime() < m_CombatAI.m_LastTimeProjectileShotAtMe + interval); } const Stuff::Point3D& CombatTacticInterface::GetProjectileOrigin() { return (m_CombatAI.m_LastProjectileOrigin); } void CombatTacticInterface::Stand() { if (m_CombatAI.GetSelf_AsVehicle() == 0) { return; } if (m_CombatAI.GetSelf_AsVehicle()->IsDerivedFrom(Mech::DefaultData) == true) { Mech* mech = Cast_Object(Mech*,m_CombatAI.GetSelf_AsVehicle()); mech->GetUpRequestRequest(); } } void CombatTacticInterface::Crouch() { m_CombatAI.Crouch(); } bool CombatTacticInterface::Crouching() const { return (m_CombatAI.Crouching()); } void CombatTacticInterface::ThrottleOverride(Stuff::Scalar duration, bool force) { m_CombatAI.ThrottleOverride(duration,force); } bool CombatTacticInterface::ShotWithin(Stuff::Scalar lastvalid) const { TIME_FUNCTION(tCombatAITime_ShotWithin); if (m_CombatAI.ShotBy(gos_GetElapsedTime() - lastvalid) != 0) { return (true); } return (false); } bool CombatTacticInterface::FiredWithin(Stuff::Scalar lastvalid) const { if (gos_GetElapsedTime() < m_CombatAI.GetLastFiredTime() + lastvalid) { return (true); } return (false); } void CombatTacticInterface::Jump() { if (CanJump() == false) { return; } m_CombatAI.OrderJump(); } void CombatTacticInterface::Jump(Stuff::Scalar duration) { if (CanJump() == false) { return; } m_CombatAI.OrderJump(duration); } void CombatTacticInterface::StopJumping() { m_CombatAI.OrderStopJumping(); } bool CombatTacticInterface::GetUnableToFireDuration(Stuff::Scalar duration) const { return (m_CombatAI.GetUnableToFireDuration(duration)); } bool CombatTacticInterface::ShouldForceDestinationRecalc() const { return (m_CombatAI.ShouldForceDestinationRecalc()); } MechWarrior4::MWObject* CombatTacticInterface::GetNearest(bool fMustBeEnemy) { return (m_CombatAI.GetNearest(fMustBeEnemy)); } int CombatTacticInterface::GetEliteLevel() const { return (m_CombatAI.EliteSkill()); } Stuff::Scalar CombatTacticInterface::GetTimeTargetedByEnemy() const { return (m_CombatAI.GetTimeTargetedByEnemy()); } Stuff::Scalar CombatTacticInterface::GetAttackThrottle() const { return (m_CombatAI.GetAttackThrottle()); } void CombatTacticInterface::ForceDestinationRecalc() { m_CombatAI.ForceDestinationRecalc(); } Stuff::Point3D CombatTacticInterface::GetMoveDest() const { return (m_CombatAI.GetMoveDest()); } Stuff::Scalar CombatTacticInterface::GetLastTimeRammedTarget() const { return (m_CombatAI.GetLastTimeRammedTarget()); } Stuff::Scalar CombatTacticInterface::GetLastTimeJumped() const { return (m_CombatAI.GetLastTimeJumped()); } Stuff::LinearMatrix4D CombatTacticInterface::GetAttackOrderPosition() const { if (m_CombatAI.m_LastAttackOrderPosition.GetPointer() == 0) { return (m_CombatAI.GetSelf().GetLocalToWorld()); } return (*(m_CombatAI.m_LastAttackOrderPosition)); } bool CombatTacticInterface::GetEscapeRegionFocusIfAvailable(Stuff::Point3D& focus) const { return (m_CombatAI.GetEscapeRegionFocusIfAvailable(focus)); } void CombatTacticInterface::SurrenderPose() { m_CombatAI.SurrenderPose(); } void CombatTacticInterface::SetSpeed(Stuff::Scalar speed) { m_CombatAI.SetSpeed(speed); } bool CombatTacticInterface::SuicideIsOK() const { return (m_CombatAI.SuicideIsOK()); } unsigned int CombatTacticInterface::NumLegsDestroyed() const { return (m_CombatAI.m_NumLegsBlownOff); } Stuff::Scalar CombatTacticInterface::GetMovementScore() const { return (m_LastMoveDestScore); } void CombatTacticInterface::SetMovementScore(Stuff::Scalar score) { m_LastMoveDestScore = score; } bool CombatTacticInterface::PointIsInBadNeighborhood(const Stuff::Point3D& point) const { return (m_CombatAI.PointIsInBadNeighborhood(point)); } bool CombatTacticInterface::ShouldRun() const { if (m_CombatAI.m_PerWeaponRayCasting == true) { return (true); } return (m_CombatAI.ShouldRun(true)); } Stuff::Scalar CombatTacticInterface::GetCombatRadiusForRange(Stuff::Scalar percentile_range) { return (m_CombatAI.GetCombatRadiusForRange(percentile_range)); } Stuff::LinearMatrix4D CombatTacticInterface::GetLastMoveOrderPosition() const { if (m_CombatAI.m_LastMoveOrderPosition.GetPointer() == 0) { return (m_CombatAI.GetSelf().GetLocalToWorld()); } return (*(m_CombatAI.m_LastMoveOrderPosition)); } Stuff::Scalar CombatTacticInterface::GetNormalizedJumpJetFuel() { if (GetSelf().IsDerivedFrom(Mech::DefaultData) == false) { return (0); } Mech* mech = Cast_Object(Mech*,&(GetSelf())); Check_Object(mech); if ((mech->GetJumpJet() == 0) || (mech->GetJumpJet()->GetGameModel() == 0) || (mech->GetJumpJet()->GetGameModel()->m_burnTime <= 0)) { return (0); } return (mech->GetJumpJet()->CurrentCharge() / mech->GetJumpJet()->GetGameModel()->m_burnTime); } bool CombatTacticInterface::CanRetreat() const { std::vector lancemates; Groups::GetLancemates(lancemates); if (std::find(lancemates.begin(),lancemates.end(),&(GetSelf())) != lancemates.end()) { return (false); } return (true); } Stuff::Scalar CombatTacticInterface::GetCurrentVulnerableComponent() { return (m_CombatAI.GetCurrentVulnerableComponent()); } bool CombatTacticInterface::CanJump() const { if (GetSelf().IsDerivedFrom(Mech::DefaultData) == false) { return (false); } Mech* mech = Cast_Object(Mech*,&GetSelf()); if ((mech->GetJumpJet() == 0) || (mech->GetJumpJet()->IsDestroyed() == true)) { return (false); } return (true); } bool CombatTacticInterface::CanCrouch() const { return (GetSelf().IsDerivedFrom(Mech::DefaultData)); } void CombatTacticInterface::FloatToPoint(const Stuff::Point3D& point) { m_CombatAI.FloatToPoint(point); } bool CombatTacticInterface::IsShootOnlyAI() const { return (m_CombatAI.IsDerivedFrom(ShooterAI::DefaultData)); } void CombatTacticInterface::SetFallDampingEnabled(bool enabled) { m_CombatAI.SetFallDampingEnabled(enabled); } Adept::ObjectID CombatTacticInterface::GetObjectID() const { return (m_CombatAI.GetSelf().objectID); } Stuff::Scalar CombatTacticInterface::GetMaxFireCheatAngle() const { return (m_CombatAI.GetMaxFireCheatAngle()); } bool CombatTacticInterface::LineMightHitFriendlyUnits(const Stuff::Line3D& line) const { return (m_CombatAI.LineMightHitFriendlyUnits(line)); } bool CombatTacticInterface::MovedWithin(Stuff::Scalar duration) const { return (m_CombatAI.MovedWithin(duration)); } void CombatTacticInterface::ContinuousFlyBy(const Stuff::Point3D& loc) { m_CombatAI.ContinuousFlyBy(loc); } bool CombatTacticInterface::RecentPathsFailed() const { return (m_CombatAI.RecentPathsFailed()); } bool CombatTacticInterface::CanMove() const { return (m_CombatAI.CanMove()); } bool CombatTacticInterface::MoveRequestPending() const { return (m_CombatAI.MoveRequestPending()); } bool CombatTacticInterface::CanTrack() const { return (m_CombatAI.CanTrack()); } bool CombatTacticInterface::CanTurn() const { return (m_CombatAI.CanTurn()); } Stuff::Scalar CombatTacticInterface::DamageTakenSinceAttackOrder() const { Stuff::Scalar damage = MW4AI::Damage::GetDamageRating(m_CombatAI.GetSelf()); return (Stuff::Fabs(damage - m_CombatAI.m_LastAttackOrderDamageRating)); } Stuff::Point3D CombatTacticInterface::GetLeashCenter() const { return (m_CombatAI.m_CombatLeash); } Stuff::Scalar CombatTacticInterface::GetLeashRadius() const { return (m_CombatAI.m_CombatLeashRadius); }