Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
580 lines
12 KiB
C++
580 lines
12 KiB
C++
#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<MWObject*> 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);
|
|
}
|