Files
firestorm/Gameleap/code/mw4/Code/MW4/AI_LancemateCommands.cpp
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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();
}