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.
292 lines
7.2 KiB
C++
292 lines
7.2 KiB
C++
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "AI_FocusFireSquad.hpp"
|
|
|
|
#include "AI_Groups.hpp"
|
|
#include "AI_UserConstants.hpp"
|
|
#include "ai_squadorders.hpp"
|
|
#include "CombatAI.hpp"
|
|
#include <Adept\NameTable.hpp>
|
|
#include "Sensor.hpp"
|
|
#pragma warning(disable : 4284)
|
|
#pragma warning (push)
|
|
#include <stlport\set>
|
|
#pragma warning (pop)
|
|
|
|
using namespace MW4AI;
|
|
using namespace MW4AI::Squad;
|
|
using namespace MechWarrior4;
|
|
|
|
const Stuff::Scalar min_target_update_time = 2.0f;
|
|
|
|
|
|
//________________________________________________________________________________________________________________
|
|
|
|
namespace MW4AI
|
|
{
|
|
namespace Squad
|
|
{
|
|
class FocusFireSquad;
|
|
};
|
|
};
|
|
|
|
class FocusFireSquadOrders
|
|
: public SquadOrders
|
|
{
|
|
public:
|
|
FocusFireSquadOrders(FocusFireSquad& squad, MechWarrior4::Group& group, int alignment);
|
|
|
|
virtual void Update();
|
|
virtual bool PointIsValid(const Stuff::Point3D& point) const;
|
|
virtual void IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command);
|
|
virtual void NotifyShotFired();
|
|
virtual MWObject* GetAutoTarget() const;
|
|
virtual bool GetExtendedSensorData(std::vector<MWObject*>& sensor_data_list) const;
|
|
virtual Stuff::Scalar GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const;
|
|
|
|
private:
|
|
FocusFireSquad& m_Squad;
|
|
MechWarrior4::Group& m_Group;
|
|
int m_Alignment;
|
|
};
|
|
|
|
FocusFireSquadOrders::FocusFireSquadOrders(FocusFireSquad& squad, MechWarrior4::Group& group, int alignment)
|
|
: m_Squad(squad)
|
|
, m_Group(group)
|
|
, m_Alignment(alignment)
|
|
{
|
|
}
|
|
|
|
void FocusFireSquadOrders::Update()
|
|
{
|
|
}
|
|
|
|
bool FocusFireSquadOrders::PointIsValid(const Stuff::Point3D& point) const
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
void FocusFireSquadOrders::IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command)
|
|
{
|
|
}
|
|
|
|
void FocusFireSquadOrders::NotifyShotFired()
|
|
{
|
|
}
|
|
|
|
MWObject* FocusFireSquadOrders::GetAutoTarget() const
|
|
{
|
|
return (m_Squad.GetAutoTarget());
|
|
}
|
|
|
|
bool FocusFireSquadOrders::GetExtendedSensorData(std::vector<MWObject*>& sensor_data_list) const
|
|
{
|
|
std::vector<MWObject*> members;
|
|
m_Group.GetMembers(members);
|
|
|
|
{for (std::vector<MWObject*>::const_iterator i_members = members.begin();
|
|
i_members != members.end();
|
|
++i_members)
|
|
{
|
|
if ((*i_members)->GetSensor() != 0)
|
|
{
|
|
{for (int i_sensor = 0;
|
|
i_sensor < (*i_members)->GetSensor()->RefreshAndGetSensorData().GetLength();
|
|
++i_sensor)
|
|
{
|
|
MechWarrior4::SensorData* d = (*i_members)->GetSensor()->RefreshAndGetSensorData()[i_sensor];
|
|
|
|
if (d != 0)
|
|
{
|
|
Adept::Entity* current = d->object.GetCurrent();
|
|
|
|
if ((current != 0) &&
|
|
(current->IsDestroyed() == false) &&
|
|
(current->IsDerivedFrom(MWObject::DefaultData) == true))
|
|
{
|
|
MWObject* target = Cast_Object(MWObject*,current);
|
|
|
|
if ((target->GetAlignment() != m_Alignment) &&
|
|
(std::find(members.begin(),members.end(),target) == members.end()) &&
|
|
(std::find(sensor_data_list.begin(),sensor_data_list.end(),target) == sensor_data_list.end()))
|
|
{
|
|
sensor_data_list.push_back(target);
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
}
|
|
}}
|
|
|
|
return (true);
|
|
}
|
|
|
|
Stuff::Scalar FocusFireSquadOrders::GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const
|
|
{
|
|
std::vector<MWObject*> members;
|
|
m_Group.GetMembers(members);
|
|
|
|
Stuff::Scalar least_distance = 0;
|
|
|
|
{for (std::vector<MWObject*>::const_iterator i_members = members.begin();
|
|
i_members != members.end();
|
|
++i_members)
|
|
{
|
|
Stuff::Scalar distance(GetLengthSquared((Stuff::Point3D)((*i_members)->GetLocalToWorld()),point));
|
|
|
|
if ((least_distance == 0) ||
|
|
(distance < least_distance))
|
|
{
|
|
least_distance = distance;
|
|
}
|
|
}}
|
|
|
|
return (least_distance);
|
|
}
|
|
|
|
|
|
//________________________________________________________________________________________________________________
|
|
|
|
FocusFireSquad::FocusFireSquad()
|
|
: m_AutoTarget(-2)
|
|
, m_LastTargetUpdateTime(0)
|
|
{
|
|
}
|
|
|
|
ID FocusFireSquad::GetID() const
|
|
{
|
|
return (GROUPAI_FOCUSFIRESQUAD);
|
|
}
|
|
|
|
template <class X>
|
|
X GetMostFrequentElement(const std::multiset<X>& m)
|
|
{
|
|
std::set<X> s(m.begin(),m.end());
|
|
|
|
std::multiset<X>::size_type best_count = 0;
|
|
X best_element = 0;
|
|
|
|
{for (std::set<X>::const_iterator i = s.begin();
|
|
i != s.end();
|
|
++i)
|
|
{
|
|
std::multiset<X>::size_type count = m.count(*i);
|
|
|
|
if (count > best_count)
|
|
{
|
|
best_element = *i;
|
|
best_count = count;
|
|
}
|
|
}}
|
|
|
|
return (best_element);
|
|
}
|
|
|
|
void FocusFireSquad::Update(MechWarrior4::Group& group, MechWarrior4::CombatAI& combat_ai)
|
|
{
|
|
inherited::Update(group,combat_ai);
|
|
|
|
if (m_LastTargetUpdateTime + min_target_update_time > (Stuff::Scalar)gos_GetElapsedTime())
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_LastTargetUpdateTime = (Stuff::Scalar)gos_GetElapsedTime();
|
|
|
|
m_AutoTarget = -2;
|
|
|
|
std::multiset<Adept::ObjectID> potential_targets;
|
|
|
|
std::vector<MWObject*> members;
|
|
group.GetMembers(members);
|
|
|
|
{for (std::vector<MWObject*>::iterator i = members.begin();
|
|
i != members.end();
|
|
++i)
|
|
{
|
|
if (((*i)->GetAI() != 0) &&
|
|
((*i)->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
|
|
{
|
|
CombatAI* combat_ai = Cast_Object(CombatAI*,(*i)->GetAI());
|
|
|
|
MWObject* target = combat_ai->FindBestAutoTarget();
|
|
|
|
if (target != 0)
|
|
{
|
|
potential_targets.insert(target->objectID);
|
|
}
|
|
}
|
|
}}
|
|
|
|
if (potential_targets.size() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_AutoTarget = GetMostFrequentElement<Adept::ObjectID>(potential_targets);
|
|
}
|
|
|
|
void FocusFireSquad::NotifyShot(MechWarrior4::Group& group, Adept::ObjectID id)
|
|
{
|
|
inherited::NotifyShot(group,id);
|
|
}
|
|
|
|
void FocusFireSquad::NotifyShotFired(MechWarrior4::Group& group, const Stuff::Line3D& line, MechWarrior4::MWObject& at_who, MechWarrior4::MWObject& shooter)
|
|
{
|
|
inherited::NotifyShotFired(group,line,at_who,shooter);
|
|
}
|
|
|
|
void FocusFireSquad::NotifyMemberAdded(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
|
|
{
|
|
inherited::NotifyMemberAdded(group,who);
|
|
|
|
if ((who.GetAI() != 0) &&
|
|
(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
|
|
{
|
|
CombatAI* combat_ai = Cast_Object(CombatAI*,who.GetAI());
|
|
#pragma warning(disable:4239)
|
|
FocusFireSquadOrders* new_squad_orders = new FocusFireSquadOrders(*this,group,who.GetAlignment());
|
|
combat_ai->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(new_squad_orders));
|
|
#pragma warning(default:4239)
|
|
}
|
|
}
|
|
|
|
void FocusFireSquad::NotifyMemberRemoved(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
|
|
{
|
|
inherited::NotifyMemberRemoved(group,who);
|
|
|
|
if ((who.GetAI() != 0) &&
|
|
(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
|
|
{
|
|
CombatAI* combat_ai = Cast_Object(CombatAI*,who.GetAI());
|
|
#pragma warning(disable:4239)
|
|
combat_ai->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(0));
|
|
#pragma warning(default:4239)
|
|
}
|
|
}
|
|
|
|
void FocusFireSquad::SetEntityToIgnore(Adept::ObjectID objectid)
|
|
{
|
|
}
|
|
|
|
MWObject* FocusFireSquad::GetAutoTarget()
|
|
{
|
|
if (m_AutoTarget < 0)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
Entity* entity = Adept::NameTable::GetInstance()->FindData(m_AutoTarget);
|
|
|
|
if ((entity == 0) ||
|
|
(entity->IsDestroyed() == true) ||
|
|
(entity->IsDerivedFrom(MWObject::DefaultData) == false))
|
|
{
|
|
m_AutoTarget = -2;
|
|
return (0);
|
|
}
|
|
|
|
return (Cast_Object(MWObject*,entity));
|
|
}
|