#include "MW4Headers.hpp" #include "AI_FireData.hpp" #include #include #include "MWMover.hpp" #include "aiutils.hpp" #include "Weapon.hpp" #include "ProjectileWeapon.hpp" #include "Vehicle.hpp" #include "MWDamageObject.hpp" #include #include 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); }