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.
210 lines
4.5 KiB
C++
210 lines
4.5 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "AI_FireData.hpp"
|
|
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\Map.hpp>
|
|
#include "MWMover.hpp"
|
|
#include "aiutils.hpp"
|
|
#include "Weapon.hpp"
|
|
#include "ProjectileWeapon.hpp"
|
|
#include "Vehicle.hpp"
|
|
#include "MWDamageObject.hpp"
|
|
#include <Adept\Entity.hpp>
|
|
#include <Adept\Site.hpp>
|
|
|
|
|
|
|
|
using namespace MW4AI;
|
|
using namespace Stuff;
|
|
|
|
extern __int64 tCombatAITime_RayCasting;
|
|
extern __int64 tRayCasting;
|
|
|
|
Stuff::Scalar ground_hit_fudge_distance = 20.0f;
|
|
|
|
|
|
// TODO: how to ensure that our lifetime is longer than the source? refcounting? will it be an issue?
|
|
|
|
FireData::FireData(Adept::Entity& source,
|
|
const Stuff::Point3D& src,
|
|
const Stuff::Point3D& dest)
|
|
: m_Query(&m_Line,&m_Normal,Adept::Entity::CanBeShotFlag,&source)
|
|
, m_Normal(1,0,0)
|
|
, m_Source(source)
|
|
{
|
|
Check_Object(&source);
|
|
|
|
CreateLine(src,dest);
|
|
}
|
|
|
|
FireData::FireData(Adept::Entity& source,
|
|
MechWarrior4::Weapon& weapon,
|
|
const Stuff::Point3D& dest)
|
|
: m_Query(&m_Line,&m_Normal,Adept::Entity::CanBeShotFlag,&source)
|
|
, m_Normal(1,0,0)
|
|
, m_Source(source)
|
|
{
|
|
Check_Object(&source);
|
|
|
|
Stuff::Point3D src;
|
|
if (weapon.sitePointer == 0)
|
|
{
|
|
src = weapon.GetParentVehicle()->GetLocalToWorld();
|
|
}
|
|
else
|
|
{
|
|
src = weapon.sitePointer->GetLocalToWorld();
|
|
}
|
|
|
|
CreateLine(src,dest);
|
|
}
|
|
|
|
void FireData::CreateLine(const Stuff::Point3D& src,
|
|
const Stuff::Point3D& dest)
|
|
{
|
|
Vector3D target_direction;
|
|
target_direction.Subtract(dest,src);
|
|
|
|
m_Line.SetOrigin(src);
|
|
|
|
if (Small_Enough(target_direction))
|
|
{
|
|
m_Line.SetDirection(UnitVector3D(1,0,0));
|
|
m_Line.m_length = 0;
|
|
}
|
|
else
|
|
{
|
|
UnitVector3D origin_direction;
|
|
|
|
if (target_direction.GetLengthSquared() == 0)
|
|
{
|
|
target_direction = Stuff::Point3D(1,0,0);
|
|
}
|
|
|
|
origin_direction.Normalize(target_direction);
|
|
m_Line.SetDirection(origin_direction);
|
|
m_Line.m_length = target_direction.GetLength();
|
|
}
|
|
}
|
|
|
|
FireData::FireData(const FireData& copy_from)
|
|
: m_Query(copy_from.m_Query)
|
|
, m_Normal(copy_from.m_Normal)
|
|
, m_Line(copy_from.m_Line)
|
|
, m_Source(copy_from.m_Source)
|
|
{
|
|
m_Query.m_line = &m_Line;
|
|
m_Query.m_normal = &m_Normal;
|
|
}
|
|
|
|
Adept::Entity* FireData::Project()
|
|
{
|
|
if ((Small_Enough(m_Line.m_length)) ||
|
|
(Small_Enough(m_Line.m_direction)))
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
Adept::Entity *entity_hit;
|
|
Check_Object(CollisionGrid::Instance);
|
|
|
|
{
|
|
TIME_FUNCTION(tCombatAITime_RayCasting);
|
|
TIME_FUNCTION(tRayCasting);
|
|
entity_hit = CollisionGrid::Instance->ProjectLine(&m_Query);
|
|
}
|
|
|
|
m_Query.m_raySource = entity_hit;
|
|
|
|
return (entity_hit);
|
|
}
|
|
|
|
FireData::HIT_RESULT FireData::GetHitResult(Adept::Entity* desired_target, bool ignore_dead_components) const
|
|
{
|
|
Verify(Adept::Map::GetInstance() != 0);
|
|
|
|
if (desired_target == 0)
|
|
{
|
|
if ((m_Query.m_raySource == 0) ||
|
|
(m_Query.m_raySource == Adept::Map::GetInstance()))
|
|
{
|
|
return (HIT_TARGET);
|
|
}
|
|
|
|
return (HIT_SOMETHING_ELSE);
|
|
}
|
|
|
|
Check_Object(desired_target);
|
|
|
|
if (m_Query.m_raySource == 0)
|
|
{
|
|
return (HIT_NOTHING);
|
|
}
|
|
|
|
if ((m_Query.m_raySource == Adept::Map::GetInstance()) &&
|
|
(m_Query.m_line != 0))
|
|
{
|
|
if (m_Query.m_line->m_length + ground_hit_fudge_distance > GetApproximateLength(GetOrigin(),(Stuff::Point3D)desired_target->GetLocalToWorld()))
|
|
{
|
|
return (HIT_NOTHING);
|
|
}
|
|
|
|
return (HIT_SOMETHING_ELSE);
|
|
}
|
|
|
|
if (m_Query.m_raySource->IsDerivedFrom(MWMover::DefaultData) == false)
|
|
{
|
|
if (m_Query.m_raySource == desired_target)
|
|
{
|
|
return (HIT_TARGET);
|
|
}
|
|
|
|
return (HIT_SOMETHING_ELSE);
|
|
}
|
|
|
|
MechWarrior4::MWMover* mover = Cast_Object(MechWarrior4::MWMover*,m_Query.m_raySource);
|
|
Check_Object(mover);
|
|
|
|
if (mover == desired_target)
|
|
{
|
|
return (HIT_TARGET);
|
|
}
|
|
|
|
if (ignore_dead_components == false)
|
|
{
|
|
if ((mover->damageObject != 0) &&
|
|
(mover->damageObject->internalDamageObject != 0) &&
|
|
(mover->damageObject->internalDamageObject->GetCurrentDamageLevel() == Adept::InternalDamageObject::Destroyed))
|
|
{
|
|
return (HIT_NOTHING);
|
|
}
|
|
}
|
|
|
|
if (mover->GetParentVehicle() == 0)
|
|
{
|
|
return (HIT_NOTHING);
|
|
}
|
|
|
|
if ((mover->GetParentVehicle() == desired_target) ||
|
|
(mover->GetParentVehicle()->GetAlignment() != m_Source.GetAlignment()))
|
|
{
|
|
return (HIT_TARGET);
|
|
}
|
|
|
|
return (HIT_SOMETHING_ELSE);
|
|
}
|
|
|
|
bool FireData::HitsGround() const
|
|
{
|
|
if ((m_Query.m_raySource != 0) &&
|
|
(m_Query.m_raySource == Adept::Map::GetInstance()) &&
|
|
(m_Query.m_line != 0))
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|