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.
897 lines
21 KiB
C++
897 lines
21 KiB
C++
//===========================================================================//
|
|
// File: MechAI.cpp //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 07/13/99 AHF Created file //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1999, Microsoft //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
#include "Adept\AdeptHeaders.hpp"
|
|
|
|
#include "mw4.hpp"
|
|
#include "planeai.hpp"
|
|
#include "Adept\Interface.hpp"
|
|
#include "Adept\Application.hpp"
|
|
#include "Adept\player.hpp"
|
|
#include "Adept\map.hpp"
|
|
#include "torso.hpp"
|
|
#include "Airplane.hpp"
|
|
#include "helicopter.hpp"
|
|
#include "dropship.hpp"
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <adept\collisionvolume.hpp>
|
|
#include "cheap_move.hpp"
|
|
#include "aiutils.hpp"
|
|
#include "dropship.hpp"
|
|
|
|
#pragma warning (push)
|
|
#include <algorithm>
|
|
#pragma warning (pop)
|
|
|
|
const int OBSTACLELOOKAHEAD = 50;
|
|
const Stuff::Time FLYBY_TIME = 1.0; // 1 second fly by
|
|
const Stuff::Scalar flyby_distance = 200.0f;
|
|
|
|
using namespace MechWarrior4;
|
|
using namespace MW4AI;
|
|
|
|
extern __int64 tMoverAITime,tDynamicObstacleTime;
|
|
|
|
//#############################################################################
|
|
//############################### AI ##############################
|
|
//#############################################################################
|
|
|
|
PlaneAI::ClassData* PlaneAI::DefaultData = NULL;
|
|
|
|
|
|
const Receiver::MessageEntry
|
|
PlaneAI::MessageEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(PlaneAI, DebugText),
|
|
};
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void PlaneAI::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
PlaneAIClassID,
|
|
"MechWarrior4::PlaneAI",
|
|
CombatAI::DefaultData,
|
|
ELEMENTS(MessageEntries), MessageEntries,
|
|
(Entity::Factory)Make,
|
|
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
|
|
NULL,
|
|
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
|
|
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
|
|
(Entity::GameModel::ModelSave)GameModel::SaveGameModel
|
|
);
|
|
Register_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void PlaneAI::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
PlaneAI* PlaneAI::Make(CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Check_Object(message);
|
|
AutoHeap local_heap (g_AIHeap);
|
|
PlaneAI *new_entity = new PlaneAI(DefaultData, message, base_id, NULL);
|
|
Check_Object(new_entity);
|
|
new_entity->SyncMatrices(true);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
PlaneAI::PlaneAI(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element)
|
|
: CombatAI(class_data, message, base_id, element),
|
|
m_ContinuousFlybySwingPoint(-1,-1,-1)
|
|
{
|
|
AutoHeap local_heap (g_AIHeap);
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
m_InMove = 0;
|
|
m_InMoveDir = 1;
|
|
|
|
m_AirLockedRects.reserve (20);
|
|
m_ObstacleAvoidPoint = Point3D (-1,-1,-1);
|
|
m_AttackRun = false;
|
|
m_Aborting = false;
|
|
m_FinishedFlyBy = false;
|
|
|
|
if (Network::GetInstance()->AmIServer())
|
|
{
|
|
Entity *ent = getEntity ();
|
|
Check_Object(ent);
|
|
Verify (ent->IsDerivedFrom (Airplane::DefaultData));
|
|
m_Airplane = Cast_Object (Airplane *,ent);
|
|
// if (!m_Airplane->IsDerivedFrom (Dropship::DefaultData))
|
|
m_Airplane->TurnOn ();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
PlaneAI::~PlaneAI()
|
|
{
|
|
}
|
|
|
|
bool PlaneAI::PointIsOK(const Stuff::Point3D& point) const
|
|
{
|
|
Check_Object (this);
|
|
Check_Object (MW4AI::g_MissionGraph);
|
|
Check_Object (m_Vehicle);
|
|
|
|
return true;
|
|
}
|
|
|
|
void PlaneAI::ClearPathLock (bool quitting,bool fromram)
|
|
{
|
|
Check_Object (this);
|
|
__int64 TempTime=GetCycles();
|
|
|
|
stlport::vector<Rect4D *>::iterator iter2;
|
|
Verify (m_AirLockedRects.size () == 0);
|
|
for (iter2 = m_AirLockedRects.begin ();iter2 != m_AirLockedRects.end ();iter2++)
|
|
{
|
|
g_AirRect4DHash->RemoveRect (*iter2);
|
|
g_AirRect4DHash->VerifyRectGone (*iter2);
|
|
delete *iter2;
|
|
}
|
|
m_AirLockedRects.clear ();
|
|
|
|
|
|
MoverAI::ClearPathLock (quitting,fromram);
|
|
tDynamicObstacleTime+=GetCycles()-TempTime;
|
|
}
|
|
|
|
bool PlaneAI::PathLock (bool secondrun,bool fromram)
|
|
{
|
|
Check_Object (this);
|
|
if (!m_Vehicle)
|
|
return false;
|
|
__int64 TempTime=GetCycles();
|
|
|
|
Check_Object (m_Vehicle);
|
|
Check_Object (m_Vehicle->GetGameModel ());
|
|
|
|
Airplane *airplane;
|
|
airplane = Cast_Object (Airplane *,m_Vehicle);
|
|
if (airplane->OnGround ())
|
|
{
|
|
MoverAI::PathLock (secondrun,fromram);
|
|
}
|
|
|
|
tDynamicObstacleTime+=GetCycles()-TempTime;
|
|
return false;
|
|
}
|
|
|
|
void PlaneAI::NotifyNoPath(void)
|
|
{
|
|
inherited::NotifyNoPath ();
|
|
}
|
|
|
|
void PlaneAI::NotifyReachedDestination(void)
|
|
{
|
|
inherited::NotifyReachedDestination ();
|
|
}
|
|
|
|
void PlaneAI::NotifyCollided(Entity *who)
|
|
{
|
|
inherited::NotifyCollided (who);
|
|
}
|
|
|
|
bool PlaneAI::AddLockRect (Rect4D *newrect,bool carecollide,Stuff::Time till)
|
|
{
|
|
delete newrect;
|
|
return false;
|
|
#if 0
|
|
Check_Object (this);
|
|
Rect4D *crect;
|
|
Point3D loc;
|
|
|
|
|
|
Check_Pointer (g_AirRect4DHash);
|
|
Check_Pointer (newrect);
|
|
|
|
if ((!carecollide) || (!m_AttackRun))
|
|
{
|
|
g_AirRect4DHash->AddRect (newrect);
|
|
m_AirLockedRects.push_back (newrect);
|
|
return false;
|
|
}
|
|
crect = g_AirRect4DHash->Collide (*newrect);
|
|
if (crect)
|
|
{
|
|
Verify (m_Vehicle);
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
UnitVector3D p1(m_Vehicle->worldSpaceVelocity.linearMotion),p2;
|
|
Point3D extra,otherloc;
|
|
Scalar dot = 5.0f;
|
|
if ((crect->who) && (crect->who->IsDerivedFrom (AI::DefaultData)))
|
|
{
|
|
AI* tempai;
|
|
tempai = (AI*) crect->who;
|
|
if (tempai->getEntity ())
|
|
{
|
|
otherloc = (Point3D) tempai->getEntity ()->GetLocalToWorld ();
|
|
extra.Subtract (otherloc,loc);
|
|
if (Small_Enough (extra.GetLength ()))
|
|
dot = 0.0f;
|
|
else
|
|
{
|
|
p2 = extra;
|
|
dot = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
}
|
|
}
|
|
if (dot > 0)
|
|
{
|
|
HandleObstacle (crect);
|
|
delete newrect;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
g_AirRect4DHash->AddRect (newrect);
|
|
m_AirLockedRects.push_back (newrect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_AirRect4DHash->AddRect (newrect);
|
|
m_AirLockedRects.push_back (newrect);
|
|
}
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool PlaneAI::Avoiding (PlaneAI *who)
|
|
{
|
|
stlport::vector<AvoidData>::iterator iter;
|
|
|
|
for (iter = m_AvoidList.begin ();iter != m_AvoidList.end ();iter++)
|
|
if (iter->who == who)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void PlaneAI::AddAvoid (PlaneAI *who)
|
|
{
|
|
AutoHeap local_heap (g_AIHeap);
|
|
stlport::vector<AvoidData>::iterator iter;
|
|
for (iter = m_AvoidList.begin ();iter != m_AvoidList.end ();iter++)
|
|
if (iter->who == who)
|
|
break;
|
|
if (iter == m_AvoidList.end ())
|
|
{
|
|
m_AvoidList.push_back (AvoidData (who,gos_GetElapsedTime ()));
|
|
}
|
|
else
|
|
{
|
|
iter->active = gos_GetElapsedTime ();
|
|
}
|
|
}
|
|
|
|
void PlaneAI::CleanAvoidList (void)
|
|
{
|
|
Stuff::Time current;
|
|
stlport::vector<AvoidData>::iterator iter;
|
|
|
|
AutoHeap local_heap (g_AIHeap);
|
|
current = gos_GetElapsedTime ();
|
|
iter = m_AvoidList.begin ();
|
|
while (iter != m_AvoidList.end ())
|
|
{
|
|
if ((iter->active - current) >= 2.0)
|
|
iter = m_AvoidList.erase (iter);
|
|
else
|
|
iter++;
|
|
}
|
|
}
|
|
|
|
void PlaneAI::RemoveAvoid (PlaneAI *who)
|
|
{
|
|
stlport::vector<AvoidData>::iterator iter;
|
|
AutoHeap local_heap (g_AIHeap);
|
|
|
|
for (iter = m_AvoidList.begin ();iter != m_AvoidList.end ();iter++)
|
|
if (iter->who == who)
|
|
break;
|
|
if (iter != m_AvoidList.end ())
|
|
{
|
|
m_AvoidList.erase (iter);
|
|
}
|
|
}
|
|
|
|
void PlaneAI::KillAvoidList (void)
|
|
{
|
|
AutoHeap local_heap (g_AIHeap);
|
|
m_AvoidList.clear ();
|
|
}
|
|
|
|
Point3D PlaneAI::FindAvoidPoint (Rect4D *rect)
|
|
{
|
|
Point3D head;
|
|
|
|
Check_Object (rect->who);
|
|
Verify (rect->who->IsDerivedFrom (PlaneAI::DefaultData));
|
|
Check_Object (m_Vehicle);
|
|
PlaneAI *plane = Cast_Object (PlaneAI *,rect->who);
|
|
Check_Object (plane->m_Vehicle);
|
|
|
|
head.x = ((rect->right - rect->left) / 2.0f) + rect->left;
|
|
head.z = ((rect->bottom - rect->top) / 2.0f) + rect->top;
|
|
head.y = 0;
|
|
|
|
Scalar rad1aa,rad2aa;
|
|
CollisionVolume *col1,*col2;
|
|
col1 = m_Vehicle->GetHierarchicalVolume ();
|
|
if (!col1)
|
|
col1 = m_Vehicle->GetSolidVolume ();
|
|
if (!col1)
|
|
rad1aa = 15.0f;
|
|
else
|
|
rad1aa = col1->m_localSpaceBounds.sphereRadius;
|
|
col2 = plane->m_Vehicle->GetHierarchicalVolume ();
|
|
if (!col2)
|
|
col2 = plane->m_Vehicle->GetSolidVolume ();
|
|
if (!col2)
|
|
rad2aa = 15.0f;
|
|
else
|
|
rad2aa = col2->m_localSpaceBounds.sphereRadius;
|
|
|
|
rad1aa *= 1.2f;
|
|
rad2aa *= 1.2f;
|
|
|
|
Vector3D dir;
|
|
if (Small_Enough (rect->velocity.linearMotion.GetLengthSquared ()))
|
|
{
|
|
dir.x = 1;
|
|
dir.y = 0;
|
|
dir.z = 0;
|
|
}
|
|
else
|
|
dir.Normalize (rect->velocity.linearMotion);
|
|
dir *= (rad1aa+rad2aa);
|
|
head -= dir;
|
|
|
|
return head;
|
|
}
|
|
|
|
void PlaneAI::AttackRunDone (void)
|
|
{
|
|
m_AttackRun = false;
|
|
m_Aborting = false;
|
|
m_FinishedFlyBy = true;
|
|
}
|
|
|
|
void PlaneAI::EndAttackRun (void)
|
|
{
|
|
if (m_Aborting)
|
|
return;
|
|
m_EndStart = gos_GetElapsedTime ();
|
|
m_Aborting = true;
|
|
}
|
|
|
|
void PlaneAI::AbortAttackRun (void)
|
|
{
|
|
Check_Object (m_Airplane);
|
|
m_EndStart = gos_GetElapsedTime ()-FLYBY_TIME;
|
|
m_Aborting = true;
|
|
m_Airplane->m_Attacking = false;
|
|
}
|
|
|
|
bool PlaneAI::ValidAttackPoint (const Point3D& point)
|
|
{
|
|
Check_Object (m_Vehicle);
|
|
|
|
Point3D endpt,extra;
|
|
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
|
|
endpt.Subtract (point,loc);
|
|
endpt.y = 0;
|
|
extra.Normalize (endpt);
|
|
Check_Object (m_Vehicle->GetGameModel ());
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
extra *= ((float) (FLYBY_TIME * (double) model->maxSpeed));
|
|
extra += point;
|
|
return g_MissionGraph->AirQuickCheck ((int) loc.x,(int) loc.z,(int) extra.x,(int) extra.z);
|
|
}
|
|
|
|
bool PlaneAI::FlyBy (const Point3D& point)
|
|
{
|
|
if (m_FinishedFlyBy)
|
|
return true;
|
|
|
|
if ((m_Aborting) || (m_AttackRun))
|
|
return false;
|
|
|
|
return (!StartAttackRun (point));
|
|
}
|
|
|
|
void PlaneAI::ContinuousFlyBy(const Point3D& point)
|
|
{
|
|
if (m_ContinuousFlybySwingPoint != Point3D(-1,-1,-1))
|
|
{
|
|
FlyBy(point);
|
|
}
|
|
|
|
if ((m_FinishedFlyBy == true) ||
|
|
((m_CurMove == 0) && (m_OrderSpeed == 0)))
|
|
{
|
|
if ((m_ContinuousFlybySwingPoint == Point3D(-1,-1,-1)) ||
|
|
(m_CurMove == 0))
|
|
{
|
|
Stuff::Point3D& p = m_ContinuousFlybySwingPoint;
|
|
p = point;
|
|
|
|
switch (gos_rand() & 0x03)
|
|
{
|
|
case 0:
|
|
{
|
|
p.x += flyby_distance;
|
|
p.z += flyby_distance;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
p.x -= flyby_distance;
|
|
p.z += flyby_distance;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
p.x += flyby_distance;
|
|
p.z -= flyby_distance;
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
p.x -= flyby_distance;
|
|
p.z -= flyby_distance;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Clamp(p.x,MW4AI::MinX,MW4AI::MaxX);
|
|
Clamp(p.z,MW4AI::MinZ,MW4AI::MaxZ);
|
|
|
|
ClearMoveOrder();
|
|
orderMoveToLocPoint(p,1000,true,false);
|
|
|
|
return;
|
|
}
|
|
|
|
Point3D my_pos(vehicle->GetLocalToWorld());
|
|
m_ContinuousFlybySwingPoint.y = my_pos.y;
|
|
|
|
if ((m_CurMove == 0) ||
|
|
(m_CurMove->Done() == true) ||
|
|
(GetApproximateLength(m_ContinuousFlybySwingPoint,my_pos) < 50))
|
|
{
|
|
ClearMoveOrder();
|
|
m_ContinuousFlybySwingPoint = Point3D(-1,-1,-1);
|
|
m_FinishedFlyBy = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool PlaneAI::StartAttackRun (const Point3D& attackpoint)
|
|
{
|
|
Verify (m_Vehicle);
|
|
m_FinishedFlyBy = false;
|
|
if ((m_Aborting) || (m_AttackRun))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ValidAttackPoint (attackpoint))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ClearMoveOrder ();
|
|
Scalar height;
|
|
|
|
BYTE material;
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
height = GetMapY (attackpoint.x,attackpoint.z,m_Vehicle,material,loc.y);
|
|
m_AttackPoint = attackpoint;
|
|
if (attackpoint.y < (height+g_MaxAirHeight))
|
|
{
|
|
m_AttackPoint.y = height + g_MaxAirHeight;
|
|
}
|
|
|
|
m_AttackRun = true;
|
|
m_Aborting = false;
|
|
m_OrderSpeed = 1.0f;
|
|
m_Airplane->m_Attacking = true;
|
|
m_Airplane->m_AttackAltitude = g_MaxAirHeight;
|
|
return true;
|
|
}
|
|
|
|
void PlaneAI::HandleObstacle (MW4AI::Rect4D *p1,Adept::Entity *p2)
|
|
{
|
|
if (p1) // potential collision
|
|
{
|
|
Verify (m_AttackRun);
|
|
|
|
Verify (p1->who);
|
|
Verify (p1->who->IsDerivedFrom (PlaneAI::DefaultData));
|
|
PlaneAI *plane = Cast_Object (PlaneAI *,p1->who);
|
|
|
|
Point3D loc(m_Airplane->GetLocalToWorld ()),otherloc (plane->m_Airplane->GetLocalToWorld ());
|
|
|
|
if (otherloc.y < loc.y) // only avoid plane lower than us since we are decending
|
|
{
|
|
AbortAttackRun ();
|
|
}
|
|
|
|
#if 0
|
|
Point3D head;
|
|
|
|
if (!plane->Avoiding (this))
|
|
{
|
|
head = FindAvoidPoint (p1);
|
|
|
|
CommandEntry *com;
|
|
com = CreateTurnToCommand (head,false);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
AddAvoid (plane);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else if (p2)
|
|
{
|
|
STOP (("plane ran into another object"));
|
|
}
|
|
else
|
|
{
|
|
STOP (("somehow a plane went up a slope that was too steep"));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PlaneAI::PathDone (Stuff::Time till,bool failed)
|
|
{
|
|
Verify (m_Vehicle);
|
|
|
|
NotifyReachedDestination ();
|
|
if ((m_CurMove->MoveType () == MOVE_PATROL) || (m_CurMove->MoveType () == MOVE_SEMIPATROL))
|
|
{
|
|
CPatrolData *tempmove;
|
|
tempmove = (CPatrolData *) m_CurMove;
|
|
switch (tempmove->PatrolType ())
|
|
{
|
|
case PATROL_SINGLE:
|
|
m_CurMove->Done (true);
|
|
break;
|
|
case PATROL_LOOP:
|
|
m_InMove = 0;
|
|
m_InMoveDir = 1;
|
|
break;
|
|
case PATROL_SEESAW:
|
|
m_InMoveDir *= -1;
|
|
m_InMove += m_InMoveDir;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
m_CurMove->Done (true);
|
|
if (m_Vehicle->IsDerivedFrom (Helicopter::DefaultData))
|
|
{
|
|
CommandEntry *com;
|
|
com = CreateSetSpeedCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
}
|
|
|
|
void PlaneAI::ExecuteMoveHead (Stuff::Time till)
|
|
{
|
|
if (m_NewMoveHead != m_MoveHead)
|
|
{
|
|
m_MoveHead = m_NewMoveHead;
|
|
m_NeedHeadingAdjust = true;
|
|
}
|
|
if (m_NewOutVec != m_OutVec)
|
|
{
|
|
m_OutVec = m_NewOutVec;
|
|
}
|
|
if (m_NewSpeedRequest != m_SpeedRequest)
|
|
{
|
|
m_SpeedRequest = m_NewSpeedRequest;
|
|
}
|
|
|
|
}
|
|
|
|
void PlaneAI::ExecutePath (Stuff::Time till)
|
|
{
|
|
Verify (m_Vehicle);
|
|
if ((!m_CurMove) && (!(((m_Aborting) || (m_AttackRun)))))
|
|
return;
|
|
Stuff::Scalar dist,move,yvalue;
|
|
CommandEntry *com;
|
|
Point3D head(0,0,0),destloc,extra;
|
|
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
Stuff::Scalar speed;
|
|
|
|
speed = m_Vehicle->speedDemand;
|
|
yvalue = loc.y;
|
|
loc.y = 0;
|
|
|
|
if (m_AttackRun)
|
|
{
|
|
if (!ValidAttackPoint (m_AttackPoint))
|
|
{
|
|
AbortAttackRun ();
|
|
}
|
|
|
|
destloc = m_AttackPoint;
|
|
}
|
|
else
|
|
{
|
|
destloc = m_CurMove->Location (m_InMove);
|
|
}
|
|
destloc.y = 0;
|
|
extra.Subtract (destloc,loc);
|
|
dist = extra.GetLengthSquared ();
|
|
move = (float) (speed * model->maxSpeed); // use one second buffer
|
|
move *= move;
|
|
|
|
if ((dist<25.0) || (dist < move))
|
|
{
|
|
if (m_AttackRun)
|
|
{
|
|
EndAttackRun ();
|
|
}
|
|
else if ((m_InMoveDir > 0) && (m_CurMove->LocationSize () > (m_InMove+m_InMoveDir)))
|
|
{
|
|
m_InMove+=m_InMoveDir;
|
|
}
|
|
else if ((m_InMoveDir < 0) && ((m_InMove+m_InMoveDir) > 0))
|
|
{
|
|
m_InMove+= m_InMoveDir;
|
|
}
|
|
else
|
|
{
|
|
PathDone (till);
|
|
}
|
|
}
|
|
|
|
if (m_AttackRun)
|
|
{
|
|
head = m_AttackPoint;
|
|
}
|
|
else
|
|
{
|
|
head = m_CurMove->Location (m_InMove);
|
|
}
|
|
if (m_Aborting)
|
|
{
|
|
BYTE material;
|
|
Scalar height;
|
|
|
|
if ((m_EndStart+FLYBY_TIME) <= gos_GetElapsedTime ())
|
|
{
|
|
Check_Object (m_Airplane);
|
|
m_Airplane->m_Attacking = false;
|
|
}
|
|
height = GetMapY (loc.x,loc.z,m_Vehicle,material,yvalue);
|
|
if (yvalue >= (height + m_Airplane->flyingAltitude))
|
|
{
|
|
AttackRunDone ();
|
|
}
|
|
else
|
|
{
|
|
m_NewMoveHead = Point3D (-1,-1,-1);
|
|
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_NewMoveHead = Point3D (-1,-1,-1);
|
|
com = CreateTurnToCommand (head,false);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
m_NewSpeedRequest = m_OrderSpeed;
|
|
com = CreateSetSpeedCommand (m_OrderSpeed);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
void PlaneAI::ExecuteMoveCommand (Stuff::Time till)
|
|
{
|
|
Verify (m_Vehicle);
|
|
|
|
if (!m_CurMove)
|
|
return;
|
|
|
|
if (m_CurMove->Done ())
|
|
return;
|
|
|
|
if (!m_CurMove->Executing ())
|
|
{
|
|
m_CurMove->Executing (true);
|
|
m_OrderSpeed = m_CurMove->Speed ();
|
|
}
|
|
else
|
|
{
|
|
m_OrderSpeed = m_CurMove->Speed ();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void PlaneAI::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
AI_LOGIC("Pre-Collision::Plane AI");
|
|
|
|
//
|
|
//---------------------------------
|
|
// Verify that this always executes
|
|
//---------------------------------
|
|
//
|
|
Check_Object(executionState);
|
|
Verify(executionState->GetState() != ExecutionStateEngine::NeverExecuteState);
|
|
m_Deactive = false;
|
|
|
|
CleanAvoidList ();
|
|
CombatAI::PreCollisionExecute(till);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void PlaneAI::DebugTextMessageHandler(Adept::ReceiverDataMessageOf<int> *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == DebugTextMessageID);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void PlaneAI::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
void PlaneAI::TurnOn (void)
|
|
{
|
|
}
|
|
|
|
void PlaneAI::TurnOff (void)
|
|
{
|
|
m_Deactive = false;
|
|
}
|
|
|
|
void PlaneAI::ExecuteMoveCommand (MW4AI::CommandEntry *command)
|
|
{
|
|
Verify (m_Vehicle);
|
|
Check_Pointer (command);
|
|
|
|
ClearMoveOrder ();
|
|
|
|
m_CurMove = (CMoveData *) command->DataPtr ();
|
|
|
|
Stuff::Point3D temp;
|
|
temp = (Stuff::Point3D) m_Vehicle->GetLocalToWorld ();
|
|
m_CurMove->CreatePlaneRequests (temp);
|
|
m_OrderSpeed = m_CurMove->Speed ();
|
|
m_InMove = 0;
|
|
m_InMoveDir = 1;
|
|
|
|
Check_Pointer (m_CurMove);
|
|
}
|
|
|
|
void PlaneAI::hellteleport (void)
|
|
{
|
|
Check_Object(m_Vehicle);
|
|
Verify(m_Vehicle->IsDerivedFrom(Airplane::DefaultData));
|
|
Airplane *flyer = Cast_Object(Airplane *, m_Vehicle);
|
|
flyer->executionState->RequestState(Airplane::ExecutionStateEngine::NeverExecuteState);
|
|
}
|
|
|
|
bool PlaneAI::orderTakeOff (int distance)
|
|
{
|
|
Check_Object(m_Vehicle);
|
|
Verify(m_Vehicle->IsDerivedFrom(Airplane::DefaultData));
|
|
Airplane *flyer = Cast_Object(Airplane *, m_Vehicle);
|
|
if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::NeverExecuteState)
|
|
flyer->TakeOff((Scalar)distance);
|
|
else if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::AlwaysExecuteState)
|
|
flyer->TakeOff((Scalar)distance);
|
|
else if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::TaxiState)
|
|
flyer->TakeOff((Scalar)distance);
|
|
else if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::FlyingMotionState)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool PlaneAI::orderLand (void)
|
|
{
|
|
Check_Object(m_Vehicle);
|
|
Verify(m_Vehicle->IsDerivedFrom(Helicopter::DefaultData));
|
|
ClearMoveOrder ();
|
|
Helicopter *flyer = Cast_Object(Helicopter *, m_Vehicle);
|
|
if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::NeverExecuteState)
|
|
return true;
|
|
else if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::AlwaysExecuteState)
|
|
return true;
|
|
else if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::TaxiState)
|
|
return true;
|
|
else if(flyer->executionState->GetState() == Airplane::ExecutionStateEngine::FlyingMotionState)
|
|
flyer->Land();
|
|
|
|
return false;
|
|
}
|
|
bool PlaneAI::orderDoorOpen(void)
|
|
{
|
|
Check_Object(m_Vehicle);
|
|
Verify(m_Vehicle->IsDerivedFrom(Dropship::DefaultData));
|
|
ClearMoveOrder ();
|
|
Dropship *drop = Cast_Object(Dropship *, m_Vehicle);
|
|
return drop->orderDoorOpen();
|
|
|
|
}
|
|
|
|
bool PlaneAI::orderDoorClose(void)
|
|
{
|
|
Check_Object(m_Vehicle);
|
|
Verify(m_Vehicle->IsDerivedFrom(Dropship::DefaultData));
|
|
ClearMoveOrder ();
|
|
Dropship *drop = Cast_Object(Dropship *, m_Vehicle);
|
|
return drop->orderDoorClose();
|
|
}
|
|
|
|
void PlaneAI::orderMoveLookOut (void)
|
|
{
|
|
if (!m_Active)
|
|
return;
|
|
gosREPORT (false,"Cannot give a lookout order to a plane");
|
|
}
|
|
|
|
void PlaneAI::orderMoveSit (bool shutdown)
|
|
{
|
|
if (!m_Active)
|
|
return;
|
|
gosREPORT (false,"Cannot give a sit order to a plane");
|
|
}
|