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.
1519 lines
36 KiB
C++
1519 lines
36 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "AI_LancemateCommands.hpp"
|
|
|
|
#include "CombatAI.hpp"
|
|
#include "MWMission.hpp"
|
|
#include "AI_FindObject.hpp"
|
|
#include "AI_Groups.hpp"
|
|
#include "VehicleInterface.hpp"
|
|
#include "Flag.hpp"
|
|
#include "Field_Base.hpp"
|
|
#include "AI_Damage.hpp"
|
|
#include "NavPoint.hpp"
|
|
#include <Adept\AudioCommand.hpp>
|
|
#include <Adept\AudioRenderer.hpp>
|
|
#include <Stuff\Auto_Ptr.hpp>
|
|
#include "lancemate.hpp"
|
|
#include <Adept\CollisionVolume.hpp>
|
|
#pragma warning(push)
|
|
#include <stlport\algorithm>
|
|
#pragma warning(pop)
|
|
|
|
|
|
using namespace MechWarrior4;
|
|
using namespace MW4AI;
|
|
using namespace MW4AI::LancemateCommands;
|
|
using namespace MW4AI::LancemateAudio;
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Adept::Entity* AttackTargetIfOK(CombatAI& combat_ai, Adept::Entity* target, LancemateAudio::AudioManager& audio_manager,bool bPlayAudio = true);
|
|
|
|
MWObject* MWObjectForID(Adept::ObjectID id)
|
|
{
|
|
Adept::Entity* entity = NameTable::GetInstance()->FindData(id);
|
|
|
|
if ((entity == 0) ||
|
|
(entity->IsDestroyed() == true) ||
|
|
(entity->IsDerivedFrom(MWObject::DefaultData) == false))
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
return (Cast_Object(MWObject*,entity));
|
|
}
|
|
|
|
inline MWObject* GetLeader(Group& group)
|
|
{
|
|
return (MWObjectForID(group.GetElements()[0]));
|
|
}
|
|
|
|
inline MWObject* GetLeader(MWObject& mwobject)
|
|
{
|
|
Group& group = Groups::GetGroup(*(mwobject.GetGroups().begin()));
|
|
return (GetLeader(group));
|
|
}
|
|
|
|
int GetMemberIndex(Group& group, CombatAI& combat_ai)
|
|
{
|
|
int index = index_of(group.GetElements().begin(),group.GetElements().end(),combat_ai.GetSelf().objectID);
|
|
Verify(index < group.GetElements().size()); // if this fails, the lancemate does not belong to the group
|
|
|
|
return (index);
|
|
}
|
|
|
|
void EnterFormationAtIndex(CombatAI& combat_ai, int index, Adept::Entity* who_to_follow)
|
|
{
|
|
int offset_x(0);
|
|
int offset_y(0);
|
|
|
|
if (combat_ai.Crouching() == true)
|
|
{
|
|
combat_ai.Crouch();
|
|
}
|
|
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
{
|
|
return;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
offset_x = 30;
|
|
offset_y = -30;
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
{
|
|
offset_x = -30;
|
|
offset_y = -30;
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
{
|
|
offset_x = 0;
|
|
offset_y = -60;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Verify(!"Lancemate::OrderFormation() not yet designed for groups of more than 4 units.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
combat_ai.orderMoveFollow(who_to_follow,offset_x,offset_y,1000);
|
|
}
|
|
|
|
void EnterFormation(CombatAI& combat_ai,
|
|
MWObject& leader)
|
|
{
|
|
if (!&leader || (leader.objectID == combat_ai.GetSelf().objectID))
|
|
{
|
|
return;
|
|
}
|
|
|
|
combat_ai.Reset(true);
|
|
|
|
MWObject::GroupList::iterator shared_group = std::find_first_of(leader.GetGroups().begin(),
|
|
leader.GetGroups().end(),
|
|
combat_ai.GetSelf().GetGroups().begin(),
|
|
combat_ai.GetSelf().GetGroups().end());
|
|
|
|
if (shared_group == leader.GetGroups().end()) { // jcem
|
|
if (combat_ai.GetSelf().GetGroups().size()) {
|
|
shared_group = combat_ai.GetSelf().GetGroups().begin();
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
int index = GetMemberIndex(Groups::GetGroup(*shared_group),combat_ai);
|
|
if (index == 0)
|
|
{
|
|
index = 3; // return...
|
|
}
|
|
|
|
EnterFormationAtIndex(combat_ai,index,&leader);
|
|
}
|
|
|
|
enum FaceForward_Result
|
|
{
|
|
DOING_SOMETHING,
|
|
FACING,
|
|
UN_CROUCHING
|
|
};
|
|
|
|
FaceForward_Result FaceForwardIfInFormation(CombatAI& combat_ai,
|
|
MWObject& leader)
|
|
{
|
|
if ((combat_ai.MoveDone() == true) &&
|
|
(combat_ai.GetAttackState() == CombatAI::NOT_ATTACKING))
|
|
{
|
|
if (leader.IsDerivedFrom(Vehicle::DefaultData) == true)
|
|
{
|
|
Vehicle* vehicle = Cast_Object(Vehicle*,&leader);
|
|
|
|
if ((vehicle->currentSpeedKPH > 10.0f) ||
|
|
(GetLengthSquared((Stuff::Point3D)combat_ai.GetSelf().GetLocalToWorld(),(Stuff::Point3D)leader.GetLocalToWorld()) > 80.0f * 80.0f))
|
|
{
|
|
EnterFormation(combat_ai,leader);
|
|
return (DOING_SOMETHING);
|
|
}
|
|
}
|
|
|
|
Stuff::UnitVector3D unit_forward;
|
|
leader.GetLocalToWorld().GetLocalForwardInWorld(&unit_forward);
|
|
Stuff::Point3D forward(unit_forward);
|
|
|
|
Stuff::UnitVector3D my_unit_forward;
|
|
combat_ai.GetSelf().GetLocalToWorld().GetLocalForwardInWorld(&my_unit_forward);
|
|
Stuff::Point3D my_forward(my_unit_forward);
|
|
|
|
Vector3D cross_product;
|
|
cross_product.Cross(forward,my_forward);
|
|
|
|
if ((cross_product.GetLengthSquared() > (0.25f * 0.25f)) &&
|
|
(combat_ai.Crouching() == true))
|
|
{
|
|
combat_ai.Crouch();
|
|
return (UN_CROUCHING);
|
|
}
|
|
|
|
forward *= 100.0f;
|
|
forward += (Stuff::Point3D)combat_ai.GetSelf().GetLocalToWorld();
|
|
|
|
combat_ai.FacePointOrLookOut(forward);
|
|
|
|
return (FACING);
|
|
}
|
|
|
|
return (DOING_SOMETHING);
|
|
}
|
|
|
|
void EnsureActive(CombatAI& combat_ai, bool stop_holding_fire = true)
|
|
{
|
|
combat_ai.Reset(true);
|
|
|
|
if (stop_holding_fire == true)
|
|
{
|
|
combat_ai.SetHoldingFire(false);
|
|
}
|
|
|
|
if (combat_ai.CanAct() == false)
|
|
{
|
|
combat_ai.Startup();
|
|
}
|
|
if (combat_ai.Crouching() == true)
|
|
{
|
|
combat_ai.Crouch();
|
|
}
|
|
}
|
|
|
|
Adept::Entity* AttackTargetIfOK(CombatAI& combat_ai, Adept::Entity* target, LancemateAudio::AudioManager& audio_manager,bool bPlayAudio/* = true*/)
|
|
{
|
|
if ((target == 0) ||
|
|
(target->IsDestroyed() == true))
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
if (target->GetAlignment() == combat_ai.GetSelf().GetAlignment())
|
|
{
|
|
if (bPlayAudio)
|
|
audio_manager.PlayAudio(AUDIO_NO,combat_ai);
|
|
return (0);
|
|
}
|
|
|
|
if (target->IsDerivedFrom(MWObject::DefaultData) == true)
|
|
{
|
|
MWObject* mwobject = Cast_Object(MWObject*,target);
|
|
|
|
if (mwobject->GetTargetDesirability() == MWObject::desirability_never)
|
|
{
|
|
if (bPlayAudio)
|
|
audio_manager.PlayAudio(AUDIO_NO,combat_ai);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
combat_ai.Reset();
|
|
combat_ai.Target(target);
|
|
|
|
if (combat_ai.Target() == 0)
|
|
{
|
|
if (bPlayAudio)
|
|
audio_manager.PlayAudio(AUDIO_NO,combat_ai);
|
|
return (0);
|
|
}
|
|
|
|
combat_ai.OrderAttack();
|
|
|
|
return (target);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
LancemateCommand::LancemateCommand(CombatAI& combat_ai,
|
|
MWObject& leader,
|
|
LancemateAudio::AudioManager& audio_manager,
|
|
Adept::Entity* pTarget2/* = NULL*/)
|
|
: m_CombatAI(combat_ai), m_AudioManager(audio_manager)
|
|
{
|
|
m_Leader.Add(&leader);
|
|
if (pTarget2)
|
|
m_pTarget2.Add(pTarget2);
|
|
Check_Object(&combat_ai);
|
|
Check_Object(&leader);
|
|
}
|
|
|
|
LancemateCommand::~LancemateCommand()
|
|
{
|
|
}
|
|
|
|
bool LancemateCommand::OnLeash() const
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
Stuff::Point3D LancemateCommand::GetLeashPoint() const
|
|
{
|
|
if (m_pTarget2.GetCurrent())
|
|
return ((Stuff::Point3D)m_pTarget2.GetCurrent()->GetLocalToWorld());
|
|
if (m_Leader.GetCurrent())
|
|
return ((Stuff::Point3D)m_Leader.GetCurrent()->GetLocalToWorld());
|
|
return Stuff::Point3D(0.0, 0.0, 0.0);
|
|
}
|
|
|
|
Stuff::Scalar LancemateCommand::GetLeashRadius() const
|
|
{
|
|
return (UserConstants::Instance()->Get(UserConstants::max_lancemate_distance_from_leader));
|
|
}
|
|
|
|
bool LancemateCommand::CanDistract() const
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
bool LancemateCommand::CanDeviateFromPath() const
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
MWObject* LancemateCommand::FindSomeoneToAttack(const Adept::ObjectID* except_who, FindObject::Criteria criteria, Stuff::Scalar radius) const
|
|
{
|
|
if ((m_CombatAI.GetSelf().GetSensor() == 0) ||
|
|
(m_CombatAI.GetHoldingFire() == true))
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
Adept::ObjectID id = FindObject::Find(m_CombatAI.GetSelf(),
|
|
FindObject::FA_ENEMY,
|
|
FindObject::FT_DEFAULT,
|
|
criteria,
|
|
FindObject::FF_WHO_SHOT + FindObject::FF_SEEPLAYER,
|
|
radius,
|
|
except_who);
|
|
|
|
if (id <= 0)
|
|
{
|
|
if (except_who != 0)
|
|
{
|
|
id = FindObject::Find(m_CombatAI.GetSelf(),
|
|
FindObject::FA_ENEMY,
|
|
FindObject::FT_DEFAULT,
|
|
criteria,
|
|
FindObject::FF_WHO_SHOT,
|
|
radius,
|
|
0);
|
|
|
|
if (id <= 0)
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
Adept::Entity* entity = NameTable::GetInstance()->FindData(id);
|
|
|
|
if ((entity != 0) &&
|
|
(entity->IsDestroyed() == false) &&
|
|
(entity->IsDerivedFrom(MWObject::DefaultData) == true))
|
|
{
|
|
return (Cast_Object(MWObject*,entity));
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void LancemateCommand::NotifyNoPath()
|
|
{
|
|
}
|
|
|
|
|
|
namespace MW4AI
|
|
{
|
|
namespace LancemateCommands
|
|
{
|
|
class AttackPlayersTarget : public LancemateCommand { DERIVED_LancemateCommand(AttackPlayersTarget);
|
|
virtual Stuff::Point3D GetLeashPoint() const;
|
|
private:
|
|
SlotOf<Adept::Entity*> m_Target;
|
|
};
|
|
class DefendPlayersTarget : public LancemateCommand { DERIVED_LancemateCommand(DefendPlayersTarget);
|
|
virtual Stuff::Point3D GetLeashPoint() const;
|
|
private:
|
|
SlotOf<Adept::Entity*> m_Target;
|
|
};
|
|
class FormOnMe : public LancemateCommand { DERIVED_LancemateCommand(FormOnMe);
|
|
virtual bool CanDistract() const;
|
|
virtual void NotifyNoPath();
|
|
private:
|
|
bool m_GivingUp;
|
|
};
|
|
class HoldFire : public LancemateCommand { DERIVED_LancemateCommand(HoldFire); };
|
|
class GoToMyNavPoint : public LancemateCommand { DERIVED_LancemateCommand(GoToMyNavPoint);
|
|
virtual Stuff::Point3D GetLeashPoint() const;
|
|
virtual void NotifyNoPath();
|
|
private:
|
|
Stuff::Point3D m_NavPos;
|
|
bool m_PlayedReachedSound;
|
|
bool m_GivingUp;
|
|
};
|
|
class Stop : public LancemateCommand { DERIVED_LancemateCommand(Stop); };
|
|
class Shutdown : public LancemateCommand { DERIVED_LancemateCommand(Shutdown);
|
|
private:
|
|
bool m_ShuttingDown;
|
|
};
|
|
class AttackNearestThreat : public LancemateCommand { DERIVED_LancemateCommand(AttackNearestThreat);
|
|
virtual Stuff::Point3D GetLeashPoint() const;
|
|
private:
|
|
SlotOf<Adept::Entity*> m_Target;
|
|
};
|
|
|
|
// not yet implemented ...
|
|
class RepairAtNearestRepairBay : public LancemateCommand { DERIVED_LancemateCommand(RepairAtNearestRepairBay);
|
|
virtual Stuff::Point3D GetLeashPoint() const;
|
|
virtual ~RepairAtNearestRepairBay();
|
|
virtual void NotifyNoPath();
|
|
virtual bool CanInterrupt() const;
|
|
|
|
private:
|
|
void StartMoving();
|
|
bool Reset();
|
|
private:
|
|
Adept::ObjectID m_MFB;
|
|
Stuff::Point3D m_LastMovePoint;
|
|
Stuff::Point3D m_MovePoints[2];
|
|
int m_NumRetries;
|
|
bool m_IssuedSetMoveHead;
|
|
};
|
|
};
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Stuff::Auto_Ptr<LancemateCommands::LancemateCommand> LancemateCommands::CreateLancemateCommand(ID command,
|
|
CombatAI& combat_ai,
|
|
MWObject& leader,
|
|
LancemateAudio::AudioManager& audio_manager,
|
|
Adept::Entity* pTarget2/* = NULL*/)
|
|
{
|
|
Verify(command > LANCEMATE_FIRST);
|
|
Verify(command < LANCEMATE_LAST);
|
|
|
|
switch (command)
|
|
{
|
|
case LANCEMATE_DEFAULT: { return (new Default(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_ATTACKPLAYERSTARGET: { return (new AttackPlayersTarget(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_DEFENDPLAYERSTARGET: { return (new DefendPlayersTarget(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_FORMONME: { return (new FormOnMe(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_HOLDFIRE: { return (new HoldFire(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_GOTOMYNAVPOINT: { return (new GoToMyNavPoint(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_STOP: { return (new Stop(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_SHUTDOWN: { return (new Shutdown(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_ATTACKNEARESTTHREAT: { return (new AttackNearestThreat(combat_ai,leader,audio_manager,pTarget2)); }
|
|
case LANCEMATE_REPAIRATNEARESTREPAIRBAY: { return (new RepairAtNearestRepairBay(combat_ai,leader,audio_manager,pTarget2)); }
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool Default::Finished() const
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
void Default::Init()
|
|
{
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
if (m_CombatAI.GetSelf().IsPlayerVehicle() == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_LastTarget.Remove();
|
|
m_LastTimeNotWaiting = (Stuff::Scalar)gos_GetElapsedTime();
|
|
EnterFormation(m_CombatAI,*pLeader);
|
|
m_CombatAI.SetAutoTargeting(true);
|
|
}
|
|
|
|
void Default::Update()
|
|
{
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
if (!pLeader)
|
|
return;
|
|
if (m_CombatAI.GetSelf().IsPlayerVehicle() == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_CombatAI.GetTimeTargetedByFriendly() > 0.5f)
|
|
{
|
|
EnterFormation(m_CombatAI,*pLeader);
|
|
}
|
|
else
|
|
{
|
|
if (m_LastTarget.GetCurrent() != m_CombatAI.Target())
|
|
{
|
|
if ((m_CombatAI.Target() == 0) ||
|
|
(m_CombatAI.Target()->IsDestroyed() == true))
|
|
{
|
|
EnterFormation(m_CombatAI,*pLeader);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_LastTarget.Remove();
|
|
if (m_CombatAI.Target())
|
|
m_LastTarget.Add(m_CombatAI.Target());
|
|
|
|
switch (FaceForwardIfInFormation(m_CombatAI,*pLeader))
|
|
{
|
|
case DOING_SOMETHING:
|
|
{
|
|
m_LastTimeNotWaiting = (Stuff::Scalar)gos_GetElapsedTime();
|
|
break;
|
|
}
|
|
|
|
case UN_CROUCHING:
|
|
{
|
|
m_LastTimeNotWaiting = (Stuff::Scalar)gos_GetElapsedTime() - 8.0f;
|
|
break;
|
|
}
|
|
|
|
case FACING:
|
|
{
|
|
Stuff::Scalar wait_time = 20.0f;
|
|
wait_time += (Stuff::Scalar)(m_CombatAI.GetSelf().objectID % 0x08);
|
|
|
|
if ((m_LastTimeNotWaiting + wait_time < gos_GetElapsedTime()) &&
|
|
(m_CombatAI.Crouching() == false))
|
|
{
|
|
m_CombatAI.Crouch();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Default::CanDistract() const
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
bool Default::CanDeviateFromPath() const
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
void Default::NotifyNoPath()
|
|
{
|
|
m_CombatAI.Reset();
|
|
Init();
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool AttackPlayersTarget::Finished() const
|
|
{
|
|
Adept::Entity* pTarget = m_Target.GetCurrent();
|
|
if (pTarget == 0)
|
|
{
|
|
return (true);
|
|
}
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
|
|
if (pTarget->IsDestroyed() == true)
|
|
{
|
|
if (!pTarget2)
|
|
m_AudioManager.PlayAudio(LancemateAudio::AUDIO_TARGETDESTROYED,m_CombatAI);
|
|
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
void AttackPlayersTarget::Init()
|
|
{
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
if (!pTarget2) // jcem
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
EnsureActive(m_CombatAI);
|
|
m_CombatAI.SetAutoTargeting(false);
|
|
|
|
Adept::Entity* pTarget = NULL;
|
|
m_Target.Remove();
|
|
|
|
if (!pTarget2) { // jcem
|
|
if (pLeader->IsDerivedFrom(Vehicle::DefaultData) == true)
|
|
{
|
|
Vehicle* leader_as_vehicle = Cast_Object(Vehicle*,pLeader);
|
|
if ((leader_as_vehicle->vehicleInterface != 0) &&
|
|
(leader_as_vehicle->vehicleInterface->m_interfaceTarget.GetCurrent() != 0))
|
|
{
|
|
Adept::Entity* entity = leader_as_vehicle->vehicleInterface->m_interfaceTarget.GetCurrent();
|
|
|
|
if (entity->IsDerivedFrom(MWObject::DefaultData) == true)
|
|
{
|
|
MWObject* mwobject = Cast_Object(MWObject*,entity);
|
|
|
|
if ((m_CombatAI.GetAttackState() != CombatAI::ATTACKING) ||
|
|
(m_CombatAI.Target() != mwobject))
|
|
{
|
|
pTarget = mwobject;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((pTarget == 0) &&
|
|
(pLeader->GetAI() != 0) &&
|
|
(pLeader->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false))
|
|
{
|
|
CombatAI* combat_ai = Cast_Object(CombatAI*,pLeader->GetAI());
|
|
Check_Object(combat_ai);
|
|
|
|
pTarget = combat_ai->Target();
|
|
}
|
|
} else { // jcem
|
|
if ((m_CombatAI.GetAttackState() != CombatAI::ATTACKING) ||
|
|
(m_CombatAI.Target() != pTarget2))
|
|
{
|
|
pTarget = pTarget2;
|
|
}
|
|
}
|
|
|
|
pTarget = AttackTargetIfOK(m_CombatAI,pTarget,m_AudioManager,m_pTarget2.GetCurrent() ? false: true);
|
|
if (pTarget)
|
|
m_Target.Add(pTarget);
|
|
}
|
|
|
|
void AttackPlayersTarget::Update()
|
|
{
|
|
}
|
|
|
|
Stuff::Point3D AttackPlayersTarget::GetLeashPoint() const
|
|
{
|
|
Adept::Entity* pTarget = m_Target.GetCurrent();
|
|
if ((pTarget == 0) ||
|
|
(pTarget->IsDestroyed() == true))
|
|
{
|
|
return (LancemateCommand::GetLeashPoint());
|
|
}
|
|
|
|
return ((Stuff::Point3D)pTarget->GetLocalToWorld());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool DefendPlayersTarget::Finished() const
|
|
{
|
|
Adept::Entity* pTarget = m_Target.GetCurrent();
|
|
if ((pTarget == 0) ||
|
|
(pTarget->IsDestroyed() == true))
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
void DefendPlayersTarget::Init()
|
|
{
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
EnsureActive(m_CombatAI);
|
|
m_CombatAI.SetAutoTargeting(false);
|
|
|
|
Adept::Entity* pTarget = NULL;
|
|
m_Target.Remove();
|
|
|
|
if (!pTarget2) { // jcem
|
|
if (pLeader->IsDerivedFrom(Vehicle::DefaultData) == true)
|
|
{
|
|
Vehicle* leader_as_vehicle = Cast_Object(Vehicle*,pLeader);
|
|
if ((leader_as_vehicle->vehicleInterface != 0) &&
|
|
(leader_as_vehicle->vehicleInterface->m_interfaceTarget.GetCurrent() != 0))
|
|
{
|
|
Adept::Entity* entity = leader_as_vehicle->vehicleInterface->m_interfaceTarget.GetCurrent();
|
|
|
|
if (entity->IsDerivedFrom(MWObject::DefaultData) == true)
|
|
{
|
|
MWObject* mwobject = Cast_Object(MWObject*,entity);
|
|
|
|
if ((m_CombatAI.GetAttackState() != CombatAI::ATTACKING) ||
|
|
(m_CombatAI.GetCurrentTactic() != Tactics::TACTIC_DEFEND) ||
|
|
(m_CombatAI.Target() != mwobject))
|
|
{
|
|
if (mwobject->GetAlignment() != m_CombatAI.GetSelf().GetAlignment())
|
|
{
|
|
m_AudioManager.PlayAudio(AUDIO_NO,m_CombatAI);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
pTarget = mwobject;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((pTarget == 0) &&
|
|
(pLeader->GetAI() != 0) &&
|
|
(pLeader->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false))
|
|
{
|
|
CombatAI* combat_ai = Cast_Object(CombatAI*,pLeader->GetAI());
|
|
Check_Object(combat_ai);
|
|
|
|
if (combat_ai->Target()->GetAlignment() == m_CombatAI.GetSelf().GetAlignment())
|
|
{
|
|
pTarget = combat_ai->Target();
|
|
}
|
|
}
|
|
} else { // jcem
|
|
if ((m_CombatAI.GetAttackState() != CombatAI::ATTACKING) ||
|
|
(m_CombatAI.GetCurrentTactic() != Tactics::TACTIC_DEFEND) ||
|
|
(m_CombatAI.Target() != pTarget2))
|
|
{
|
|
if (pTarget2->GetAlignment() != m_CombatAI.GetSelf().GetAlignment())
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
pTarget = pTarget2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((pTarget != 0) &&
|
|
(pTarget->IsDestroyed() == true))
|
|
{
|
|
pTarget = 0;
|
|
}
|
|
|
|
if (pTarget != 0)
|
|
{
|
|
m_Target.Add(pTarget);
|
|
m_CombatAI.Reset();
|
|
m_CombatAI.Target(pTarget);
|
|
m_CombatAI.OrderAttackTactic(Tactics::TACTIC_DEFEND);
|
|
|
|
if (!pTarget2)
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
}
|
|
}
|
|
|
|
void DefendPlayersTarget::Update()
|
|
{
|
|
}
|
|
|
|
Stuff::Point3D DefendPlayersTarget::GetLeashPoint() const
|
|
{
|
|
Adept::Entity* pTarget = m_Target.GetCurrent();
|
|
if ((pTarget == 0) ||
|
|
(pTarget->IsDestroyed() == true))
|
|
{
|
|
return (LancemateCommand::GetLeashPoint());
|
|
}
|
|
|
|
return ((Stuff::Point3D)pTarget->GetLocalToWorld());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool FormOnMe::Finished() const
|
|
{
|
|
if (m_CombatAI.MoveDone() == true) {
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
if (pTarget2) {
|
|
if (GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),(Stuff::Point3D)pTarget2->GetLocalToWorld()) < 80.0f * 80.0f)
|
|
return (true);
|
|
} else if (pLeader) {
|
|
if (GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),(Stuff::Point3D)pLeader->GetLocalToWorld()) < 80.0f * 80.0f)
|
|
return (true);
|
|
}
|
|
}
|
|
|
|
return (m_GivingUp);
|
|
}
|
|
|
|
bool FormOnMe::CanDistract() const
|
|
{
|
|
if (m_CombatAI.MoveDone() == true) {
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
if (pTarget2) {
|
|
if (GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),(Stuff::Point3D)pTarget2->GetLocalToWorld()) < 80.0f * 80.0f)
|
|
return (true);
|
|
} else {
|
|
if (GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),(Stuff::Point3D)pLeader->GetLocalToWorld()) < 80.0f * 80.0f)
|
|
return (true);
|
|
}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
void FormOnMe::Init()
|
|
{
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
if (!pTarget2)
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
EnsureActive(m_CombatAI,false);
|
|
m_CombatAI.SetAutoTargeting(true);
|
|
|
|
m_GivingUp = false;
|
|
|
|
if (pTarget2)
|
|
EnterFormation(m_CombatAI,*(MWObject*)pTarget2);
|
|
else
|
|
EnterFormation(m_CombatAI,*pLeader);
|
|
}
|
|
|
|
void FormOnMe::Update()
|
|
{
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
if (pTarget2)
|
|
FaceForwardIfInFormation(m_CombatAI,*(MWObject*)pTarget2);
|
|
else
|
|
FaceForwardIfInFormation(m_CombatAI,*pLeader);
|
|
}
|
|
|
|
void FormOnMe::NotifyNoPath()
|
|
{
|
|
m_GivingUp = true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool HoldFire::Finished() const
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
void HoldFire::Init()
|
|
{
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
if (m_CombatAI.GetHoldingFire() == true)
|
|
{
|
|
m_CombatAI.SetHoldingFire(false);
|
|
}
|
|
else
|
|
{
|
|
m_CombatAI.SetHoldingFire(true);
|
|
}
|
|
}
|
|
|
|
void HoldFire::Update()
|
|
{
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool GoToMyNavPoint::Finished() const
|
|
{
|
|
return (m_GivingUp);
|
|
}
|
|
|
|
void GoToMyNavPoint::Init()
|
|
{
|
|
MechWarrior4::MWObject* pLeader = m_Leader.GetCurrent();
|
|
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
EnsureActive(m_CombatAI,false);
|
|
m_CombatAI.SetAutoTargeting(true);
|
|
|
|
m_PlayedReachedSound = false;
|
|
m_GivingUp = false;
|
|
|
|
if (m_CombatAI.GetSelf().IsDerivedFrom(Vehicle::DefaultData) == false)
|
|
{
|
|
m_NavPos = LancemateCommand::GetLeashPoint();
|
|
return;
|
|
}
|
|
|
|
Vehicle* leader_as_vehicle = Cast_Object(Vehicle*,pLeader);
|
|
if ((leader_as_vehicle->vehicleInterface == 0) ||
|
|
(leader_as_vehicle->vehicleInterface->m_selectedNavPoint.GetCurrent() == 0))
|
|
{
|
|
m_NavPos = LancemateCommand::GetLeashPoint();
|
|
return;
|
|
}
|
|
|
|
m_NavPos = (Stuff::Point3D)(leader_as_vehicle->vehicleInterface->m_selectedNavPoint.GetCurrent()->GetLocalToWorld());
|
|
|
|
m_CombatAI.Reset();
|
|
m_CombatAI.MoveToPoint(m_NavPos);
|
|
}
|
|
|
|
void GoToMyNavPoint::Update()
|
|
{
|
|
if ((m_PlayedReachedSound == false) &&
|
|
(GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),m_NavPos) < 150.0f * 150.0f))
|
|
{
|
|
m_PlayedReachedSound = true;
|
|
|
|
m_AudioManager.PlayAudio(LancemateAudio::AUDIO_ATNAV,m_CombatAI);
|
|
}
|
|
}
|
|
|
|
Stuff::Point3D GoToMyNavPoint::GetLeashPoint() const
|
|
{
|
|
return (m_NavPos);
|
|
}
|
|
|
|
void GoToMyNavPoint::NotifyNoPath()
|
|
{
|
|
m_GivingUp = true;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool Stop::Finished() const
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
void Stop::Init()
|
|
{
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
m_CombatAI.Reset();
|
|
m_CombatAI.SetAutoTargeting(true);
|
|
}
|
|
|
|
void Stop::Update()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool Shutdown::Finished() const
|
|
{
|
|
if (m_ShuttingDown == true)
|
|
{
|
|
if (m_CombatAI.CanAct() == false)
|
|
{
|
|
return (true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_CombatAI.CanAct() == true)
|
|
{
|
|
return (true);
|
|
}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
void Shutdown::Init()
|
|
{
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
if (m_CombatAI.Crouching() == true)
|
|
{
|
|
m_CombatAI.Crouch();
|
|
}
|
|
|
|
if (m_CombatAI.CanAct() == true)
|
|
{
|
|
m_ShuttingDown = true;
|
|
m_CombatAI.Shutdown();
|
|
}
|
|
else
|
|
{
|
|
m_ShuttingDown = false;
|
|
m_CombatAI.Startup();
|
|
}
|
|
}
|
|
|
|
void Shutdown::Update()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool AttackNearestThreat::Finished() const
|
|
{
|
|
Adept::Entity* pTarget = m_Target.GetCurrent();
|
|
if ((pTarget == 0) ||
|
|
(pTarget->IsDestroyed() == true))
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
Stuff::Point3D AttackNearestThreat::GetLeashPoint() const
|
|
{
|
|
Adept::Entity* pTarget = m_Target.GetCurrent();
|
|
if ((pTarget == 0) ||
|
|
(pTarget->IsDestroyed() == true))
|
|
{
|
|
return (LancemateCommand::GetLeashPoint());
|
|
}
|
|
|
|
return ((Stuff::Point3D)pTarget->GetLocalToWorld());
|
|
}
|
|
|
|
void AttackNearestThreat::Init()
|
|
{
|
|
Adept::Entity* pTarget2 = m_pTarget2.GetCurrent();
|
|
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
EnsureActive(m_CombatAI);
|
|
m_CombatAI.SetAutoTargeting(true);
|
|
|
|
m_Target.Remove();
|
|
|
|
Update();
|
|
MWObject* nearest_enemy = FindSomeoneToAttack(0,FindObject::FC_NEAREST);
|
|
|
|
Adept::Entity* pTarget = AttackTargetIfOK(m_CombatAI,nearest_enemy,m_AudioManager,pTarget2 ? false: true);
|
|
if (pTarget)
|
|
m_Target.Add(pTarget);
|
|
}
|
|
|
|
void AttackNearestThreat::Update()
|
|
{
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
template <class T>
|
|
T* FindByID(Adept::ObjectID id, Adept::Entity::ClassData* classdata)
|
|
{
|
|
if (id == -2)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
Adept::Entity* entity = NameTable::GetInstance()->FindData(id);
|
|
|
|
if ((entity == 0) ||
|
|
(entity->IsDestroyed() == true) ||
|
|
(entity->IsDerivedFrom(classdata) == false))
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
return (Cast_Object(T*,entity));
|
|
}
|
|
|
|
Adept::ObjectID FindNearestFieldBase(const Stuff::Point3D& pos, Stuff::ChainOf<MFB*>& chain)
|
|
{
|
|
Stuff::ChainIteratorOf<MFB*> i(&chain);
|
|
|
|
MFB* t = 0;
|
|
Stuff::Scalar least_distance = 0;
|
|
MFB* best = 0;
|
|
while ((t = i.ReadAndNext()) != 0)
|
|
{
|
|
if (t->IsDerivedFrom(FieldBase::DefaultData) == true)
|
|
{
|
|
Stuff::Scalar distance(GetLengthSquared(pos,(Stuff::Point3D)t->GetLocalToWorld()));
|
|
if ((least_distance == 0) ||
|
|
(distance < least_distance))
|
|
{
|
|
best = t;
|
|
least_distance = distance;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (best == 0)
|
|
{
|
|
return (-2);
|
|
}
|
|
|
|
return (best->objectID);
|
|
}
|
|
|
|
Stuff::Point3D GetPointInFrontOfObject(Adept::Entity& entity, bool front, Stuff::Scalar collision_volume_radius_multiplier)
|
|
{
|
|
const Stuff::LinearMatrix4D& matrix = entity.GetLocalToWorld();
|
|
|
|
Stuff::UnitVector3D unit_vector;
|
|
|
|
if (front == true)
|
|
{
|
|
matrix.GetLocalForwardInWorld(&unit_vector);
|
|
}
|
|
else
|
|
{
|
|
matrix.GetLocalBackwardInWorld(&unit_vector);
|
|
}
|
|
|
|
CollisionVolume* cv = entity.GetSolidVolume();
|
|
|
|
Stuff::Point3D rv(matrix);
|
|
if (cv == 0)
|
|
{
|
|
return (rv);
|
|
}
|
|
|
|
Stuff::Scalar radius = cv->m_worldSpaceBounds.sphereRadius * collision_volume_radius_multiplier;
|
|
|
|
Stuff::Point3D add(unit_vector);
|
|
add *= radius;
|
|
|
|
rv += add;
|
|
|
|
return (rv);
|
|
}
|
|
|
|
bool RepairAtNearestRepairBay::Finished() const
|
|
{
|
|
if (m_NumRetries > 3)
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
if (m_CombatAI.ExitedFieldBaseRecently() == true)
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if (mfb == 0)
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
bool RepairAtNearestRepairBay::Reset()
|
|
{
|
|
EnsureActive(m_CombatAI,false);
|
|
|
|
m_LastMovePoint = Stuff::Point3D(0,0,0);
|
|
m_MovePoints[0] = m_LastMovePoint;
|
|
m_MovePoints[1] = m_LastMovePoint;
|
|
|
|
m_MFB = FindNearestFieldBase((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),*(MFB::s_MFBs));
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if ((mfb && (mfb->m_CurrentMechUsing != &m_CombatAI) && (mfb->m_CurrentMechUsing != NULL)) ||
|
|
(MW4AI::Damage::CanRepair(m_CombatAI.GetSelf()) == false))
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
StartMoving();
|
|
return (true);
|
|
}
|
|
|
|
void RepairAtNearestRepairBay::Init()
|
|
{
|
|
Verify(MFB::s_MFBs != 0);
|
|
|
|
m_AudioManager.PlayAudio(AUDIO_OK,m_CombatAI);
|
|
m_NumRetries = 0;
|
|
m_IssuedSetMoveHead = false;
|
|
|
|
if (Reset() == false)
|
|
{
|
|
m_AudioManager.PlayAudio(LancemateAudio::AUDIO_NO,m_CombatAI);
|
|
m_NumRetries = 4;
|
|
}
|
|
}
|
|
|
|
void RepairAtNearestRepairBay::StartMoving()
|
|
{
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if (mfb == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
mfb->m_CurrentMechUsing = &m_CombatAI;
|
|
Stuff::Point3D forward = GetPointInFrontOfObject(*mfb,true,1.9f);
|
|
Stuff::Point3D backward = GetPointInFrontOfObject(*mfb,false,1.9f);
|
|
|
|
if (GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),forward) <
|
|
GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),backward))
|
|
{
|
|
m_MovePoints[0] = forward;
|
|
m_MovePoints[1] = GetPointInFrontOfObject(*mfb,true,0.5f);
|
|
}
|
|
else
|
|
{
|
|
m_MovePoints[0] = backward;
|
|
m_MovePoints[1] = GetPointInFrontOfObject(*mfb,false,0.5f);
|
|
}
|
|
|
|
m_LastMovePoint = m_MovePoints[0];
|
|
|
|
m_CombatAI.Reset();
|
|
m_CombatAI.orderMoveToLocPoint(m_LastMovePoint,60,true,false);
|
|
}
|
|
|
|
void RepairAtNearestRepairBay::Update()
|
|
{
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if (mfb == 0)
|
|
{
|
|
m_MFB = FindNearestFieldBase((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),*(MFB::s_MFBs));
|
|
mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if (mfb != 0)
|
|
{
|
|
StartMoving();
|
|
}
|
|
}
|
|
|
|
if (mfb != 0)
|
|
{
|
|
if ((m_CombatAI.CanAct() == true) &&
|
|
(m_CombatAI.MovedWithin(4.0f) == false))
|
|
{
|
|
++m_NumRetries;
|
|
|
|
if (m_NumRetries > 3)
|
|
{
|
|
m_AudioManager.PlayAudio(AUDIO_NO,m_CombatAI);
|
|
}
|
|
else
|
|
{
|
|
m_CombatAI.m_LastTimeMoved = (Stuff::Scalar)gos_GetElapsedTime();
|
|
|
|
if (m_NumRetries > 2)
|
|
{
|
|
NotifyNoPath();
|
|
}
|
|
else
|
|
{
|
|
Reset();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_LastMovePoint == m_MovePoints[0])
|
|
{
|
|
Stuff::Point3D pos(m_CombatAI.GetSelf().GetLocalToWorld());
|
|
Stuff::Point3D dest = m_LastMovePoint;
|
|
|
|
if (m_CombatAI.getCurPath() != 0)
|
|
{
|
|
dest = m_CombatAI.getCurPath()->End();
|
|
}
|
|
|
|
if (GetLengthSquared(pos,dest) < 20 * 20)
|
|
{
|
|
m_LastMovePoint = m_MovePoints[1];
|
|
|
|
m_CombatAI.ClearMoveOrder ();
|
|
m_CombatAI.Reset();
|
|
m_CombatAI.SetRamTarget(mfb);
|
|
|
|
Check_Object (m_CombatAI.getVehicle()->GetGameModel ());
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_CombatAI.getVehicle()->GetGameModel ()) ;
|
|
Scalar normalspeed = ((float) ConvertKPHtoMPS(30)) / ((float) model->maxSpeed);
|
|
Scalar endspeed = ((float) ConvertKPHtoMPS(30)) / ((float) model->maxSpeed);
|
|
|
|
m_CombatAI.SetMoveHead (m_LastMovePoint,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
m_IssuedSetMoveHead = true;
|
|
// m_CombatAI.orderMoveToLocPoint(m_LastMovePoint,600,true,false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Stuff::Point3D RepairAtNearestRepairBay::GetLeashPoint() const
|
|
{
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if (mfb != 0)
|
|
{
|
|
return ((Stuff::Point3D)mfb->GetLocalToWorld());
|
|
}
|
|
|
|
return (LancemateCommand::GetLeashPoint());
|
|
}
|
|
|
|
RepairAtNearestRepairBay::~RepairAtNearestRepairBay()
|
|
{
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if ((mfb != 0) &&
|
|
(mfb->m_CurrentMechUsing == &m_CombatAI))
|
|
{
|
|
mfb->m_CurrentMechUsing = 0;
|
|
}
|
|
}
|
|
|
|
void RepairAtNearestRepairBay::NotifyNoPath()
|
|
{
|
|
MFB* mfb = FindByID<MFB>(m_MFB,MFB::DefaultData);
|
|
|
|
if (mfb == 0)
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
|
|
mfb->m_CurrentMechUsing = &m_CombatAI;
|
|
Stuff::Point3D forward = GetPointInFrontOfObject(*mfb,true,1.9f);
|
|
Stuff::Point3D backward = GetPointInFrontOfObject(*mfb,false,1.9f);
|
|
|
|
if (m_MovePoints[0] == backward)
|
|
{
|
|
m_MovePoints[0] = forward;
|
|
m_MovePoints[1] = GetPointInFrontOfObject(*mfb,true,0.5f);
|
|
}
|
|
else
|
|
{
|
|
m_MovePoints[0] = backward;
|
|
m_MovePoints[1] = GetPointInFrontOfObject(*mfb,false,0.5f);
|
|
}
|
|
|
|
m_LastMovePoint = m_MovePoints[0];
|
|
|
|
m_CombatAI.Reset();
|
|
m_CombatAI.orderMoveToLocPoint(m_LastMovePoint,600,true,false);
|
|
}
|
|
|
|
bool RepairAtNearestRepairBay::CanInterrupt() const
|
|
{
|
|
if (m_IssuedSetMoveHead == true)
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
return ((m_LastMovePoint == m_MovePoints[0]) ||
|
|
(m_NumRetries > 0));
|
|
}
|
|
|
|
|
|
|
|
void StandardLancemateSound(const Stuff::MString& prefix, Stuff::MString& s)
|
|
{
|
|
s = "VO\\Generic\\";
|
|
s += prefix;
|
|
s += (gos_rand() & 0x01) ? "1" : "2";
|
|
s += "_Ian.wav{handle}";
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// ExecuteForAllLancemates(): executes a LancemateFunction functor for a given list of lancemates
|
|
//
|
|
|
|
void ExecuteForAllLancemates(const lancemate_list& lancemates, LancemateCommands::ID command_id)
|
|
{
|
|
Verify(NameTable::GetInstance() != 0);
|
|
|
|
MWObject* leader = 0;
|
|
{for (lancemate_list::const_iterator i = lancemates.begin();
|
|
i != lancemates.end();
|
|
++i)
|
|
{
|
|
MWObject* mwobject = MWObjectForID(*i);
|
|
|
|
if (mwobject != 0)
|
|
{
|
|
Check_Object(mwobject);
|
|
MWObject* l = GetLeader(*mwobject);
|
|
|
|
if (l != 0)
|
|
{
|
|
Check_Object(l);
|
|
leader = l;
|
|
break;
|
|
}
|
|
}
|
|
}}
|
|
|
|
if (leader == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool notified(false);
|
|
|
|
{for (lancemate_list::const_iterator i = lancemates.begin();
|
|
i != lancemates.end();
|
|
++i)
|
|
{
|
|
MWObject* mwobject = MWObjectForID(*i);
|
|
|
|
if ((mwobject != 0) &&
|
|
(mwobject != leader) &&
|
|
(mwobject->GetAI() != 0) &&
|
|
(mwobject->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
|
|
{
|
|
|
|
if ((mwobject->GetAI() == 0) ||
|
|
(mwobject->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CombatAI* m_CombatAI = Cast_Object(CombatAI*,mwobject->GetAI());
|
|
|
|
if ((m_CombatAI->GetSquadOrders() != 0) &&
|
|
(m_CombatAI->GetSquadOrders()->CanExecuteCommands() == true))
|
|
{
|
|
if (notified == false)
|
|
{
|
|
notified = true;
|
|
|
|
Stuff::MString s("");
|
|
switch (command_id)
|
|
{
|
|
case LANCEMATE_ATTACKPLAYERSTARGET: StandardLancemateSound("Attack",s); break;
|
|
case LANCEMATE_DEFENDPLAYERSTARGET: StandardLancemateSound("Defend",s); break;
|
|
case LANCEMATE_FORMONME: StandardLancemateSound("Form",s); break;
|
|
case LANCEMATE_HOLDFIRE: StandardLancemateSound("Hold",s); break;
|
|
case LANCEMATE_GOTOMYNAVPOINT: StandardLancemateSound("Goto",s); break;
|
|
case LANCEMATE_STOP: StandardLancemateSound("Stop",s); break;
|
|
case LANCEMATE_SHUTDOWN: StandardLancemateSound("Shutdown",s); break;
|
|
case LANCEMATE_ATTACKNEARESTTHREAT: StandardLancemateSound("AttackNear",s); break;
|
|
case LANCEMATE_REPAIRATNEARESTREPAIRBAY: StandardLancemateSound("Repair",s); break;
|
|
}
|
|
|
|
if (s.GetLength() > 0)
|
|
{
|
|
AudioCommand *command = AudioCommand::Create(AudioRenderer::VOType, s, 1.0f, 1.0f);
|
|
if (command)
|
|
{
|
|
Check_Object(command);
|
|
command->Play();
|
|
}
|
|
}
|
|
}
|
|
|
|
Stuff::Auto_Ptr<LancemateCommand> lancemate_command(m_CombatAI->GetSquadOrders()->CreateCommand(command_id));
|
|
// Stuff::Auto_Ptr<LancemateCommand> lancemate_command(CreateLancemateCommand(command_id,*m_CombatAI,*leader,m_CombatAI->GetSquadOrders()->GetAudioManager()));
|
|
|
|
if (lancemate_command.GetPointer() != 0)
|
|
{
|
|
m_CombatAI->GetSquadOrders()->IssueCommand(lancemate_command);
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Execute(): the core, public execution function
|
|
//
|
|
|
|
void LancemateCommands::Execute(ID command, const lancemate_list& lancemates)
|
|
{
|
|
Verify(command > LANCEMATE_FIRST);
|
|
Verify(command < LANCEMATE_LAST);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
|
|
ExecuteForAllLancemates(lancemates,command);
|
|
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|
|
void LancemateCommands::ExecuteForAllLancemates2(Mech* paMechs[], int nMechs, LancemateCommands::ID command_id, MWObject* pLeader, MWObject* pTarget)
|
|
{
|
|
Verify(command_id > LANCEMATE_FIRST);
|
|
Verify(command_id < LANCEMATE_LAST);
|
|
|
|
Verify(NameTable::GetInstance() != 0);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
|
|
for (int i = 0; i < nMechs; ++i) {
|
|
MWObject* mwobject = paMechs[i];
|
|
|
|
if ((mwobject != 0) && (mwobject != pLeader)) {
|
|
AI* pAI = mwobject->GetAI();
|
|
if ((pAI != 0) && (pAI->IsDerivedFrom(CombatAI::DefaultData) == true)) {
|
|
CombatAI* pCombatAI = Cast_Object(CombatAI*,pAI);
|
|
|
|
if ((pCombatAI->GetSquadOrders() != 0) && (pCombatAI->GetSquadOrders()->CanExecuteCommands() == true))
|
|
{
|
|
Stuff::Auto_Ptr<LancemateCommand> lancemate_command(pCombatAI->GetSquadOrders()->CreateCommand(command_id,pTarget));
|
|
// Stuff::Auto_Ptr<LancemateCommand> lancemate_command(CreateLancemateCommand(command_id,m_CombatAI,*leader,m_CombatAI.GetSquadOrders()->GetAudioManager()));
|
|
|
|
if (lancemate_command.GetPointer() != 0)
|
|
{
|
|
pCombatAI->GetSquadOrders()->IssueCommand(lancemate_command);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|