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.
4401 lines
109 KiB
C++
4401 lines
109 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 "gameinfo.hpp"
|
|
#include "mw4.hpp"
|
|
#include "moverai.hpp"
|
|
#include "Adept\Interface.hpp"
|
|
#include "Adept\Application.hpp"
|
|
#include "Adept\player.hpp"
|
|
#include "torso.hpp"
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include "mwobject.hpp"
|
|
#include "building.hpp"
|
|
#include <adept\collisionvolume.hpp>
|
|
#include "move_formation.hpp"
|
|
#include "mwplayer.hpp"
|
|
#include "bridge.hpp"
|
|
#include "jumpjet.hpp"
|
|
#include "cheap_move.hpp"
|
|
#include "adept\map.hpp"
|
|
#include "dropship.hpp"
|
|
#include "field_base.hpp"
|
|
#include "shooterai.hpp"
|
|
#include "vehicleinterface.hpp"
|
|
|
|
|
|
#pragma warning (push)
|
|
#include <algorithm>
|
|
#pragma warning (pop)
|
|
|
|
const int OBSTACLELOOKAHEAD = 50;
|
|
const int MAX_FAILS_PATROL = 5;
|
|
const Scalar BOARD_RADIUS = 1.5f;
|
|
|
|
//using namespace stlport;
|
|
|
|
using namespace MechWarrior4;
|
|
using namespace MW4AI;
|
|
|
|
namespace ABL
|
|
{
|
|
extern MechWarrior4::MoverAI *CurMoverAI;
|
|
};
|
|
namespace MW4AI
|
|
{
|
|
extern __int64 tPathTime,tGridPathTime;
|
|
};
|
|
|
|
//#############################################################################
|
|
//############################### AI ##############################
|
|
//#############################################################################
|
|
|
|
MoverAI::ClassData* MoverAI::DefaultData = NULL;
|
|
__int64 tMoverAITime,tDynamicObstacleTime;
|
|
bool MoverAI::g_AlwaysIgnoreObstacles = false;
|
|
bool MoverAI::m_AIJumpAllowed = true;
|
|
|
|
|
|
const Receiver::MessageEntry
|
|
MoverAI::MessageEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(MoverAI, DebugText),
|
|
};
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MoverAI::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
MoverAIClassID,
|
|
"MechWarrior4::MoverAI",
|
|
AI::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);
|
|
|
|
#if !defined(NO_TIMERS)
|
|
AddStatistic( "MoverAI ", "%", gos_timedata, (void*)&tMoverAITime, 0 );
|
|
AddStatistic( "Dynamic Obstacle ", "%", gos_timedata, (void*)&tDynamicObstacleTime, 0 );
|
|
#endif
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MoverAI::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MoverAI* MoverAI::Make(CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Check_Object(message);
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
MoverAI *new_entity = new MoverAI(DefaultData, message, base_id, NULL);
|
|
Check_Object(new_entity);
|
|
new_entity->SyncMatrices(true);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MoverAI::MoverAI(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element)
|
|
: AI(class_data, message, base_id, element),
|
|
m_CombatLeashRadius(0)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
m_ObstacleRequest = NULL;
|
|
m_PathBlockedRect = NULL;
|
|
m_CurMove = NULL;
|
|
m_CurPath = NULL;
|
|
m_CheapMover = NULL;
|
|
m_PathBad = false;
|
|
m_RecalcTime = 0;
|
|
m_MoveHead = Stuff::Point3D (-1,-1,-1);
|
|
m_OutVec = Stuff::Point3D (-1,-1,-1);
|
|
m_NewMoveHead = Stuff::Point3D (-1,-1,-1);
|
|
m_NewOutVec = Stuff::Point3D (-1,-1,-1);
|
|
m_OldMoveHead = Stuff::Point3D (-1,-1,-1);
|
|
m_DropShipWait = Stuff::Point3D (-1,-1,-1);
|
|
m_DropShipBoard = Stuff::Point3D (-1,-1,-1);
|
|
m_DropShipCenter = Stuff::Point3D (-1,-1,-1);
|
|
m_DropShipFinal = Stuff::Point3D (-1,-1,-1);
|
|
m_BoardingDropShip = DROP_NOT_ACTIVE;
|
|
m_DropShip = NULL;
|
|
m_OtherDropShipBoarders.push_back(NULL);
|
|
m_OtherDropShipBoarders.push_back(NULL);
|
|
m_OtherDropShipBoarders.push_back(NULL);
|
|
m_OtherDropShipBoarders.push_back(NULL);
|
|
m_OtherDropShipBoarders.push_back(NULL);
|
|
m_DropShipID = 0;
|
|
m_ReadyToStart = false;
|
|
m_CanStartBoard = false;
|
|
m_CombatLeash.Zero();
|
|
m_EnteringFieldBase = FIELDBASE_NOT_ACTIVE;
|
|
|
|
m_SpeedRequest = 0;
|
|
m_NewSpeedRequest = 0;
|
|
m_EndSpeedRequest = 0;
|
|
m_NewEndSpeedRequest = 0;
|
|
SetOrderSpeed (0);
|
|
m_NeedHeadingAdjust = false;
|
|
m_NeedSpeedAdjust = false;
|
|
m_PathBlocked = false;
|
|
m_Jumping = false;
|
|
m_JumpRequested = false;
|
|
m_PathLock.reserve (10);
|
|
m_LockedRects.reserve (20);
|
|
// m_ObstacleAvoidMode = false;
|
|
m_ObstacleAvoidPoint = Point3D (-1,-1,-1);
|
|
m_RamTarget = NULL;
|
|
m_FailCount = 0;
|
|
m_TimeNotMoving = 0;
|
|
|
|
m_LastTimeFinishedFieldBase = 0;
|
|
|
|
m_Vehicle = NULL;
|
|
m_MWObject = NULL;
|
|
Entity *ent;
|
|
|
|
ent = getEntity ();
|
|
if (ent)
|
|
{
|
|
Check_Object(ent);
|
|
if (ent->IsDerivedFrom (Vehicle::DefaultData))
|
|
m_Vehicle = (Vehicle *)ent;
|
|
if (ent->IsDerivedFrom (MWObject::DefaultData))
|
|
m_MWObject = (MWObject *)ent;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MoverAI::~MoverAI()
|
|
{
|
|
Check_Object (this);
|
|
ClearPathLock (true,false);
|
|
delete m_CurMove;
|
|
m_CurMove = NULL;
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
delete m_PathBlockedRect;
|
|
if (m_CheapMover)
|
|
delete m_CheapMover;
|
|
ClearTempLockRects ();
|
|
m_CheapMover = NULL;
|
|
m_PathBlockedRect = NULL;
|
|
if (m_ObstacleRequest)
|
|
{
|
|
g_PathManager->RemoveRequest (m_ObstacleRequest);
|
|
delete m_ObstacleRequest;
|
|
m_ObstacleRequest = NULL;
|
|
}
|
|
|
|
m_ObstacleList.clear ();
|
|
|
|
Verify (m_PathLock.size () == 0);
|
|
stlport::vector<MW4AI::LockData*>::iterator iter;
|
|
for (iter = m_PathLock.begin ();iter != m_PathLock.end ();iter++)
|
|
{
|
|
delete (*iter);
|
|
}
|
|
|
|
m_PathLock.clear ();
|
|
m_LockedRects.clear ();
|
|
}
|
|
|
|
void MoverAI::Save (MemoryStream *stream)
|
|
{
|
|
if (m_Vehicle)
|
|
*stream << m_Vehicle->objectID;
|
|
else
|
|
*stream << (ObjectID) -1;
|
|
if (m_MWObject)
|
|
*stream << m_MWObject->objectID;
|
|
else
|
|
*stream << (ObjectID) -1;
|
|
|
|
if (m_CurMove)
|
|
{
|
|
*stream << true;
|
|
*stream << ((int) m_CurMove->MoveType ());
|
|
}
|
|
else
|
|
{
|
|
*stream << false;
|
|
}
|
|
if (m_CurPath)
|
|
{
|
|
*stream << true;
|
|
m_CurPath->Save (stream);
|
|
}
|
|
else
|
|
{
|
|
*stream << false;
|
|
}
|
|
*stream << m_TimeNotMoving;
|
|
*stream << m_MoveHead;
|
|
*stream << m_OutVec;
|
|
*stream << m_OldMoveHead;
|
|
*stream << m_NewMoveHead;
|
|
*stream << m_NewOutVec;
|
|
*stream << m_SpeedRequest;
|
|
*stream << m_NewSpeedRequest;
|
|
*stream << m_EndSpeedRequest;
|
|
*stream << m_NewEndSpeedRequest;
|
|
*stream << m_OrderSpeed;
|
|
*stream << m_StartJump;
|
|
*stream << m_BurnTime;
|
|
*stream << m_NeedHeadingAdjust;
|
|
*stream << m_NeedSpeedAdjust;
|
|
*stream << m_Jumping;
|
|
*stream << m_JumpRequested;
|
|
|
|
*stream << m_PathBlocked;
|
|
if (m_RamTarget)
|
|
*stream << m_RamTarget->objectID;
|
|
else
|
|
*stream << (ObjectID) -1;
|
|
|
|
*stream << m_PathBlockedCell;
|
|
if (m_PathBlockedRect)
|
|
{
|
|
*stream << true;
|
|
m_PathBlockedRect->Save (stream);
|
|
}
|
|
else
|
|
{
|
|
*stream << false;
|
|
}
|
|
*stream << m_PathBlockedRectTimeDelta;
|
|
*stream << m_LockTime;
|
|
*stream << m_RecalcTime;
|
|
*stream << m_PathBad;
|
|
*stream << m_ObstacleAvoidPoint;
|
|
*stream << m_CombatLeash;
|
|
*stream << m_CombatLeashRadius;
|
|
|
|
AI::Save(stream);
|
|
}
|
|
void MoverAI::Load (MemoryStream *stream)
|
|
{
|
|
ObjectID temp;
|
|
bool flag;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
|
|
*stream >> temp; // get attached vehicle id
|
|
if (m_Vehicle)
|
|
Verify (temp == m_Vehicle->objectID);
|
|
else
|
|
Verify (temp == -1);
|
|
*stream >> temp; // get attached mwobject id
|
|
if (m_MWObject)
|
|
Verify (temp == m_MWObject->objectID);
|
|
else
|
|
Verify (temp == -1);
|
|
|
|
*stream >> flag;
|
|
delete m_CurMove;
|
|
m_CurMove = NULL;
|
|
if (flag)
|
|
{
|
|
int move;
|
|
|
|
*stream >> move;
|
|
switch (move)
|
|
{
|
|
case MOVE_LOOKOUT:
|
|
m_CurMove = new CLookoutData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_PATROL:
|
|
m_CurMove = new CPatrolData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_SEMIPATROL:
|
|
m_CurMove = new CSemiPatrolData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_RIGIDPATROL:
|
|
m_CurMove = new CRigidPatrolData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_FLEE:
|
|
m_CurMove = new CFleeData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_FOLLOW:
|
|
m_CurMove = new CFollowData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_SIT:
|
|
m_CurMove = new CSitData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_LOCPOINT:
|
|
m_CurMove = new CMoveLocPointData (g_MissionGraph,this);
|
|
break;
|
|
case MOVE_OBJECT:
|
|
m_CurMove = new CMoveObjectData (g_MissionGraph,this);
|
|
break;
|
|
default:
|
|
STOP (("unknown type of move command in save game file"));
|
|
break;
|
|
}
|
|
Check_Pointer (m_CurMove);
|
|
m_CurMove->Load (stream);
|
|
}
|
|
*stream >> flag;
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
if (flag)
|
|
{
|
|
AutoHeap local_heap (g_RailHeap);
|
|
m_CurPath = new CRailPath (g_MissionGraph,this);
|
|
Check_Pointer (m_CurPath);
|
|
m_CurPath->Load (stream);
|
|
}
|
|
*stream >> m_TimeNotMoving;
|
|
*stream >> m_MoveHead;
|
|
*stream >> m_OutVec;
|
|
*stream >> m_OldMoveHead;
|
|
*stream >> m_NewMoveHead;
|
|
*stream >> m_NewOutVec;
|
|
*stream >> m_SpeedRequest;
|
|
*stream >> m_NewSpeedRequest;
|
|
*stream >> m_EndSpeedRequest;
|
|
*stream >> m_NewEndSpeedRequest;
|
|
*stream >> m_OrderSpeed;
|
|
*stream >> m_StartJump;
|
|
*stream >> m_BurnTime;
|
|
*stream >> m_NeedHeadingAdjust;
|
|
*stream >> m_NeedSpeedAdjust;
|
|
*stream >> m_Jumping;
|
|
*stream >> m_JumpRequested;
|
|
|
|
*stream >> m_PathBlocked;
|
|
|
|
*stream >> temp;
|
|
if (temp != -1)
|
|
{
|
|
Check_Object (NameTable::GetInstance());
|
|
m_RamTarget = Cast_Object (MWObject * ,NameTable::GetInstance()->FindData(temp));
|
|
}
|
|
else
|
|
{
|
|
m_RamTarget = NULL;
|
|
}
|
|
|
|
*stream >> m_PathBlockedCell;
|
|
*stream >> flag;
|
|
delete m_PathBlockedRect;
|
|
m_PathBlockedRect = NULL;
|
|
if (flag)
|
|
{
|
|
m_PathBlockedRect = new Rect4D ();
|
|
Check_Pointer (m_PathBlockedRect);
|
|
m_PathBlockedRect->Load (stream);
|
|
}
|
|
*stream >> m_PathBlockedRectTimeDelta;
|
|
*stream >> m_LockTime;
|
|
*stream >> m_RecalcTime;
|
|
*stream >> m_PathBad;
|
|
*stream >> m_ObstacleAvoidPoint;
|
|
*stream >> m_CombatLeash;
|
|
*stream >> m_CombatLeashRadius;
|
|
|
|
AI::Load (stream);
|
|
}
|
|
|
|
bool MoverAI::AllowTenMeter (void)
|
|
{
|
|
Check_Object (this);
|
|
Check_Object (m_Vehicle);
|
|
if (m_Vehicle->IsDerivedFrom (Mech::DefaultData))
|
|
return false;
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = m_Vehicle->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = m_Vehicle->GetSolidVolume ();
|
|
if (col)
|
|
{
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, m_Vehicle->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
ExtentBox box (*obb);
|
|
if (((box.maxX - box.minX) <= 6.0f) && (((box.maxZ - box.minZ) <= 6.0f)))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MoverAI::PointIsOK(const Stuff::Point3D& point) const
|
|
{
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
Check_Object (this);
|
|
Check_Object (MW4AI::g_MissionGraph);
|
|
Check_Object (m_Vehicle);
|
|
|
|
// if (LockedByMe (point))
|
|
// return true;
|
|
|
|
Check_Object (m_Vehicle->GetGameModel ());
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
int usage = MW4AI::ConvertTypetoUsage (model->moveTypeFlag);
|
|
int movepass = ConvertUsagetoMovePass (usage);
|
|
Check_Object (this);
|
|
int sqrindex[9][2] = {
|
|
{-1,-1},
|
|
{0,-1},
|
|
{1,-1},
|
|
{-1,0},
|
|
{1,0},
|
|
{-1,1},
|
|
{0,1},
|
|
{1,1},
|
|
{0,0}
|
|
};
|
|
int cx,cz,sx,sz;
|
|
|
|
sx = (int) point.x/10;
|
|
sz = (int) point.z/10;
|
|
int i;
|
|
for (i=0;i<9;i++)
|
|
{
|
|
cx = sx+sqrindex[i][0];
|
|
cz = sz+sqrindex[i][1];
|
|
|
|
if (BlockerLocal (cx,cz) == (MWObject *)this)
|
|
continue;
|
|
|
|
if (!g_MissionGraph->MoveTo (cx,cz,0,movepass))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
|
|
#pragma warning (disable : 4800)
|
|
// return(!(CheckCanPass(MW4AI::g_MissionGraph->Passable (point.x,point.z) , movepass)));
|
|
#pragma warning (default : 4800)
|
|
}
|
|
|
|
void MoverAI::NotifyNoPath(void)
|
|
{
|
|
Check_Object (this);
|
|
m_RecalcTime = gos_GetElapsedTime () + ((Random::GetFraction ()*2.0f)+1.0f);
|
|
m_PathBad = true;
|
|
SetMoveHead (Stuff::Point3D (-1,-1,-1),0);
|
|
SetOrderSpeed (0);
|
|
CommandEntry *com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
void MoverAI::NotifyReachedDestination(void)
|
|
{
|
|
Check_Object (this);
|
|
}
|
|
|
|
void MoverAI::NotifyCollided(Entity *who)
|
|
{
|
|
Check_Object (this);
|
|
}
|
|
|
|
bool MoverAI::EqualRamTarget (Entity *target)
|
|
{
|
|
Check_Object (this);
|
|
if (!m_RamTarget)
|
|
return false;
|
|
|
|
Entity *comp1=NULL,*comp2=NULL;
|
|
if (target->IsDerivedFrom (AI::DefaultData))
|
|
{
|
|
comp1 = ((AI*)target)->getEntity();
|
|
}
|
|
else if (target->IsDerivedFrom (MWPlayer::DefaultData))
|
|
{
|
|
comp2 = ((MWPlayer *)target)->vehicle;
|
|
}
|
|
else if (target->IsDerivedFrom (MWObject::DefaultData))
|
|
{
|
|
comp1 = (MWObject *) target;
|
|
}
|
|
|
|
if (m_RamTarget->IsDerivedFrom (AI::DefaultData))
|
|
{
|
|
comp2 = ((AI*)m_RamTarget)->getEntity ();
|
|
}
|
|
else if (m_RamTarget->IsDerivedFrom (MWPlayer::DefaultData))
|
|
{
|
|
comp2 = ((MWPlayer *)m_RamTarget)->vehicle;
|
|
}
|
|
else if (m_RamTarget->IsDerivedFrom (MWObject::DefaultData))
|
|
{
|
|
comp2 = (MWObject *) m_RamTarget;
|
|
}
|
|
if (comp1 == comp2)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void MoverAI::SlopeCollide (void)
|
|
{
|
|
Check_Object (this);
|
|
HandleObstacle ();
|
|
}
|
|
|
|
void MoverAI::HandleObstacle (MW4AI::Rect4D *p1,Adept::Entity *p2)
|
|
{
|
|
Check_Object (this);
|
|
Check_Object (m_Vehicle);
|
|
Check_Object (m_Vehicle->GetGameModel ());
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
if (!m_CurMove)
|
|
return;
|
|
if (p1)
|
|
{
|
|
if ((!p1->who) || (!p1->who->IsDerivedFrom (MoverAI::DefaultData)))
|
|
{
|
|
if ((m_CurMove) && (m_CurMove->MoveType () == MOVE_RIGIDPATROL))
|
|
m_CurMove->Done (true);
|
|
else
|
|
{
|
|
AddTempLockRect (*p1);
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
// UnTempLock ();
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Rect4D *newrect;
|
|
|
|
MoverAI *mover;
|
|
mover = Cast_Object (MoverAI *, p1->who);
|
|
if (!mover->m_PathBlocked)
|
|
{
|
|
newrect = new Rect4D;
|
|
NotifyNoPath ();
|
|
PathDone (gos_GetElapsedTime (),true);
|
|
m_PathBad = false;
|
|
m_LockTime = gos_GetElapsedTime ()+((Random::GetFraction ()*2.0f)+1.0f);
|
|
m_PathBlocked = true;
|
|
*newrect = *p1;
|
|
newrect->who = this;
|
|
m_PathBlockedRect = newrect;
|
|
m_PathBlockedRectTimeDelta = newrect->time - ((int) (gos_GetElapsedTime () * Rect4DTimeDelta));
|
|
}
|
|
else
|
|
{
|
|
AddTempLockRect (*p1);
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
// UnTempLock ();
|
|
}
|
|
}
|
|
}
|
|
else if (p2)
|
|
{
|
|
if (p2->IsDerivedFrom (Bridge::DefaultData))
|
|
return;
|
|
// if ((!p2->IsDerivedFrom (Vehicle::DefaultData)) && (!p2->IsDerivedFrom (AI::DefaultData)))
|
|
{
|
|
int mask = 0;
|
|
switch (model->moveTypeFlag)
|
|
{
|
|
case MWObject__GameModel::LEG_MOVETYPE:
|
|
mask = LEGPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::LEGJUMP_MOVETYPE:
|
|
mask = LEGPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::TRACK_MOVETYPE:
|
|
mask = TRACKPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::WHEEL_MOVETYPE:
|
|
mask = WHEELPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::HOVER_MOVETYPE:
|
|
mask = HOVERPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::WATER_MOVETYPE:
|
|
mask = WATERPASS_FLAG;
|
|
break;
|
|
default:
|
|
mask = BLOCKED_FLAGS;
|
|
break;
|
|
}
|
|
Point3D loc,buildloc;
|
|
|
|
Verify (m_Vehicle);
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
buildloc = (Point3D) p2->GetLocalToWorld ();
|
|
|
|
Rect4D lockrect;
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = p2->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = p2->GetSolidVolume ();
|
|
if (col)
|
|
{
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, p2->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
ExtentBox box (*obb);
|
|
int x,z;
|
|
int minx,maxx,minz,maxz;
|
|
|
|
minx = (int) box.minX;
|
|
maxx = (int) box.maxX;
|
|
minz = (int) box.minZ;
|
|
maxz = (int) box.maxZ;
|
|
minx /= BLOCK_GRID_RES;
|
|
maxx /= BLOCK_GRID_RES;
|
|
minz /= BLOCK_GRID_RES;
|
|
maxz /= BLOCK_GRID_RES;
|
|
if (minx < (MinX/10))
|
|
minx = (int) (MinX/10);
|
|
if (minz < (MinZ/10))
|
|
minz = (int) (MinZ/10);
|
|
if (maxx >= (MaxX/10.0f))
|
|
maxx = (int) (MaxX/10)-1;
|
|
if (maxz >= (MaxZ/10.0f))
|
|
maxz = (int) (MaxZ/10)-1;
|
|
|
|
lockrect.left = box.minX;
|
|
lockrect.right = box.maxX;
|
|
lockrect.top = box.minZ;
|
|
lockrect.bottom = box.maxZ;
|
|
|
|
bool mark = true;
|
|
if (p2->IsDerivedFrom (Vehicle::DefaultData))
|
|
{
|
|
Vehicle *veh;
|
|
veh = Cast_Object (Vehicle *,p2);
|
|
if (veh->GetAI ())
|
|
{
|
|
if (veh->GetAI ()->IsDerivedFrom (ShooterAI::DefaultData))
|
|
mark = true;
|
|
else
|
|
mark = false;
|
|
}
|
|
else
|
|
mark = true;
|
|
}
|
|
if (mark)
|
|
{
|
|
for (x=minx;x<=maxx;x++)
|
|
for (z=minz;z<=maxz;z++)
|
|
MW4AI::g_MissionGraph->PassableLocal (x,z,(unsigned short) mask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool mark = true;
|
|
if (p2->IsDerivedFrom (Vehicle::DefaultData))
|
|
{
|
|
Vehicle *veh;
|
|
veh = Cast_Object (Vehicle *,p2);
|
|
if (veh->GetAI ())
|
|
{
|
|
if (veh->GetAI ()->IsDerivedFrom (ShooterAI::DefaultData))
|
|
mark = true;
|
|
else
|
|
mark = false;
|
|
}
|
|
else
|
|
mark = true;
|
|
}
|
|
if (mark)
|
|
{
|
|
MW4AI::g_MissionGraph->Passable (buildloc.x,buildloc.z,(unsigned short) mask);
|
|
lockrect.left = buildloc.x-2.5f;
|
|
lockrect.right = buildloc.x+2.5f;
|
|
lockrect.top = buildloc.z-2.5f;
|
|
lockrect.bottom = buildloc.z+2.5f;
|
|
}
|
|
}
|
|
|
|
if ((m_CurMove) && (m_CurMove->MoveType () == MOVE_RIGIDPATROL))
|
|
m_CurMove->Done (true);
|
|
|
|
Check_Object (p2);
|
|
Check_Object (m_Vehicle);
|
|
Vector3D vector_to_target;
|
|
Point3D local_to_world(m_Vehicle->GetLocalToWorld());
|
|
Point3D target_local_to_world(p2->GetLocalToWorld());
|
|
|
|
vector_to_target.Subtract(target_local_to_world, local_to_world);
|
|
if (vector_to_target.x < 0)
|
|
lockrect.left -= BLOCK_GRID_RES;
|
|
else if (vector_to_target.x > 0)
|
|
lockrect.right += BLOCK_GRID_RES;
|
|
|
|
if (vector_to_target.z < 0)
|
|
lockrect.top -= BLOCK_GRID_RES;
|
|
else if (vector_to_target.z > 0)
|
|
lockrect.bottom += BLOCK_GRID_RES;
|
|
|
|
if (Abs (vector_to_target.x) > Abs (vector_to_target.z))
|
|
{
|
|
lockrect.top -= BLOCK_GRID_RES;
|
|
lockrect.bottom += BLOCK_GRID_RES;
|
|
}
|
|
else if (Abs (vector_to_target.x) < Abs (vector_to_target.z))
|
|
{
|
|
lockrect.left -= BLOCK_GRID_RES;
|
|
lockrect.right += BLOCK_GRID_RES;
|
|
}
|
|
|
|
AddTempLockRect (lockrect);
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
// UnTempLock ();
|
|
CommandEntry *com;
|
|
com = CreateSetSpeedCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
ClearPathLock (false,false);
|
|
PathLock (false,false); // should cause the pathlock to fail then wait for a time to recalc
|
|
if (!m_PathBlockedRect)
|
|
{
|
|
NotifyNoPath ();
|
|
PathDone (gos_GetElapsedTime (),true);
|
|
m_PathBad = false;
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
CommandEntry *com;
|
|
com = CreateSetSpeedCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Point3D loc,buildloc;
|
|
|
|
Verify (m_Vehicle);
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
|
|
int mask = 0;
|
|
switch (model->moveTypeFlag)
|
|
{
|
|
case MWObject__GameModel::LEG_MOVETYPE:
|
|
mask = LEGPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::LEGJUMP_MOVETYPE:
|
|
mask = LEGPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::TRACK_MOVETYPE:
|
|
mask = TRACKPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::WHEEL_MOVETYPE:
|
|
mask = WHEELPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::HOVER_MOVETYPE:
|
|
mask = HOVERPASS_FLAG;
|
|
break;
|
|
case MWObject__GameModel::WATER_MOVETYPE:
|
|
mask = WATERPASS_FLAG;
|
|
break;
|
|
}
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = m_Vehicle->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = m_Vehicle->GetSolidVolume ();
|
|
if (col)
|
|
{
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, m_Vehicle->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
ExtentBox box (*obb);
|
|
int x,z;
|
|
int minx,maxx,minz,maxz;
|
|
|
|
UnitVector3D forward;
|
|
Point3D fordir;
|
|
m_Vehicle->GetLocalToWorld().GetLocalForwardInWorld(&forward);
|
|
fordir = forward;
|
|
fordir *= obb->sphereRadius;
|
|
minx = (int) (box.minX+fordir.x);
|
|
maxx = (int) (box.maxX+fordir.x);
|
|
minz = (int) (box.minZ+fordir.z);
|
|
maxz = (int) (box.maxZ+fordir.z);
|
|
minx /= BLOCK_GRID_RES;
|
|
maxx /= BLOCK_GRID_RES;
|
|
minz /= BLOCK_GRID_RES;
|
|
maxz /= BLOCK_GRID_RES;
|
|
if (minx < (MinX/10))
|
|
minx = (int) (MinX/10);
|
|
if (minz < (MinZ/10))
|
|
minz = (int) (MinZ/10);
|
|
if (maxx >= (MaxX/10.0f))
|
|
maxx = (int) (MaxX/10)-1;
|
|
if (maxz >= (MaxZ/10.0f))
|
|
maxz = (int) (MaxZ/10)-1;
|
|
|
|
for (x=minx;x<=maxx;x++)
|
|
{
|
|
for (z=minz;z<=maxz;z++)
|
|
{
|
|
MW4AI::g_MissionGraph->PassableLocal (x,z,(unsigned short) mask);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
MW4AI::g_MissionGraph->Passable (loc.x,loc.z,(unsigned short) mask);
|
|
|
|
if ((m_CurMove) && (m_CurMove->MoveType () == MOVE_RIGIDPATROL))
|
|
m_CurMove->Done (true);
|
|
if ((model->moveTypeFlag != MWObject__GameModel::WATER_MOVETYPE) || (!m_Deactive))
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
}
|
|
}
|
|
|
|
bool MoverAI::ReactToCollision(Stuff::DynamicArrayOf<CollisionData> *collisions,bool& shoulddamage)
|
|
{
|
|
Check_Object (this);
|
|
|
|
shoulddamage = true;
|
|
inherited::ReactToCollision(collisions,shoulddamage);
|
|
|
|
if ((getEntity() != 0) &&
|
|
(getEntity()->IsPlayerVehicle() == false) &&
|
|
(g_AlwaysIgnoreObstacles == true))
|
|
{
|
|
bool player_vehicle = false;
|
|
|
|
{for (int i = 0; i < collisions->GetLength(); ++i) // check for player vehicle
|
|
{
|
|
CollisionData *data = &(*collisions)[i];
|
|
|
|
if (data->m_otherEntity->IsPlayerVehicle() == true)
|
|
{
|
|
player_vehicle = true;
|
|
}
|
|
}}
|
|
|
|
if (player_vehicle == false)
|
|
{
|
|
shoulddamage = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (m_EnteringFieldBase != FIELDBASE_NOT_ACTIVE)
|
|
{
|
|
shoulddamage = false;
|
|
return false;
|
|
}
|
|
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
if (loc.y <= -1500.0f)
|
|
{
|
|
shoulddamage = false;
|
|
return false;
|
|
}
|
|
if ((m_BoardingDropShip != DROP_NOT_ACTIVE) && (m_BoardingDropShip != DROP_FIRST_POINT))
|
|
{
|
|
shoulddamage = false;
|
|
return false; // ignore all collisions when trying to board dropship
|
|
}
|
|
|
|
Check_Object(this);
|
|
|
|
int i;
|
|
if (IsDerivedFrom (PlayerAI::DefaultData))
|
|
{
|
|
for ( i=0; i<collisions->GetLength(); ++i) // check for player vehicle
|
|
{
|
|
CollisionData *data = &(*collisions)[i];
|
|
|
|
if (m_Vehicle->GetAlignment () == data->m_otherEntity->GetAlignment ())
|
|
shoulddamage = false;
|
|
}
|
|
}
|
|
|
|
if (executionState->GetState() == ExecutionStateEngine::NeverExecuteState)
|
|
return true;
|
|
|
|
if (Adept::Player::GetInstance())
|
|
{
|
|
MWPlayer *player;
|
|
Check_Object (Adept::Player::GetInstance());
|
|
player = Cast_Object (MWPlayer *,Adept::Player::GetInstance());
|
|
|
|
for ( i=0; i<collisions->GetLength(); ++i) // check for player vehicle
|
|
{
|
|
CollisionData *data = &(*collisions)[i];
|
|
/*
|
|
if (data->m_otherEntity->IsDerivedFrom (Bridge::DefaultData))
|
|
{
|
|
shoulddamage = false;
|
|
return false;
|
|
}
|
|
*/
|
|
if (player->vehicle == data->m_otherEntity)
|
|
{
|
|
if (m_Vehicle->GetAlignment () == player->vehicle->GetAlignment ())
|
|
shoulddamage = false;
|
|
HandleObstacle (data->m_otherEntity);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (m_MoveHead == Stuff::Point3D (-1,-1,-1)) // ai should not be moving to handle collision
|
|
return true;
|
|
|
|
if (m_CheapMover) // outside player area so ignore collisions
|
|
{
|
|
shoulddamage = false;
|
|
return false;
|
|
}
|
|
|
|
Scalar heading_adjustment,absadjust;
|
|
Point3D distance_to_target;
|
|
LinearMatrix4D tempmat (m_Vehicle->GetLocalToWorld ());
|
|
tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis);
|
|
distance_to_target.MultiplyByInverse(m_MoveHead,tempmat);
|
|
if (m_OrderSpeed < 0) // reverse direction
|
|
{
|
|
distance_to_target.x = -distance_to_target.x;
|
|
distance_to_target.z = -distance_to_target.z;
|
|
}
|
|
if (Small_Enough(distance_to_target.z) && Small_Enough(distance_to_target.x))
|
|
distance_to_target.z = 1.0f;
|
|
heading_adjustment = Arctan(distance_to_target.x, distance_to_target.z);
|
|
absadjust = heading_adjustment<0?-1.0f*heading_adjustment:heading_adjustment;
|
|
|
|
if ((absadjust > Pi_Over_4) && (!m_Jumping))
|
|
{
|
|
return false; // ai is trying to turn away from a collision, so ignore them for now.
|
|
}
|
|
|
|
for (i=0; i<collisions->GetLength(); ++i)
|
|
{
|
|
CollisionData *data = &(*collisions)[i];
|
|
|
|
Check_Object(data);
|
|
Check_Object(data->m_otherEntity);
|
|
Verify(this != data->m_otherEntity);
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
Check_Object(m_Vehicle);
|
|
// if ((data->m_otherEntity->IsACollider()) || (data->m_otherEntity->IsACollide ()))
|
|
{
|
|
Vector3D vector_to_target;
|
|
Point3D local_to_world(m_Vehicle->GetLocalToWorld());
|
|
Point3D target_local_to_world(data->m_otherEntity->GetLocalToWorld());
|
|
if ((data->m_otherEntity->GetWalkThruType () == AnythingCanWalkThruType) && (m_Vehicle->GetClassID () == MechClassID))
|
|
return true;
|
|
vector_to_target.Subtract(target_local_to_world, local_to_world);
|
|
UnitVector3D current_motion;
|
|
if (m_OrderSpeed < 0)
|
|
m_Vehicle->GetLocalToWorld().GetLocalBackwardInWorld(¤t_motion);
|
|
else
|
|
m_Vehicle->GetLocalToWorld().GetLocalForwardInWorld(¤t_motion);
|
|
|
|
Scalar dot_product;
|
|
dot_product = current_motion * vector_to_target;
|
|
|
|
if (dot_product <= 0.0f) // collision behind us to ignore, trying to move away
|
|
continue;
|
|
|
|
if (EqualRamTarget (data->m_otherEntity))
|
|
{
|
|
shoulddamage = true;
|
|
return true;
|
|
}
|
|
|
|
HandleObstacle (data->m_otherEntity);
|
|
shoulddamage = false;
|
|
}
|
|
return true;
|
|
}
|
|
return false; // unknown type so ignore collision
|
|
}
|
|
|
|
void MoverAI::PathDone (Stuff::Time till,bool failed)
|
|
{
|
|
Check_Object (this);
|
|
if (m_CurMove)
|
|
{
|
|
m_CurMove->PathDone (this,till,failed);
|
|
}
|
|
if (!failed)
|
|
{
|
|
if ((m_CurMove) && (m_CurMove->Done ()))
|
|
NotifyReachedDestination ();
|
|
else if (!m_CurMove)
|
|
NotifyReachedDestination ();
|
|
m_FailCount = 0;
|
|
}
|
|
}
|
|
|
|
void MoverAI::SetMoveHead (const Stuff::Point3D& head,Stuff::Scalar speedreq,const Stuff::Point3D& outvec,Stuff::Scalar endspeed)
|
|
{
|
|
Check_Object (this);
|
|
m_NewMoveHead = head;
|
|
m_NewOutVec = outvec;
|
|
if (m_NewMoveHead == Point3D (-1,-1,-1))
|
|
{
|
|
speedreq = 0;
|
|
}
|
|
m_NewSpeedRequest = speedreq;
|
|
m_NewEndSpeedRequest = endspeed < speedreq ? endspeed : speedreq;
|
|
}
|
|
|
|
void MoverAI::ClearPathLock (bool quitting,bool fromram)
|
|
{
|
|
Check_Object (this);
|
|
MOVER_LOGIC("ClearPathLock");
|
|
#if !defined(NO_TIMERS)
|
|
my_AutoTimer fred ((void *) &tDynamicObstacleTime);
|
|
#endif
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
Verify (m_LockedRects.size () == 0);
|
|
stlport::vector<Rect4D *>::iterator iter2;
|
|
for (iter2 = m_LockedRects.begin ();iter2 != m_LockedRects.end ();iter2++)
|
|
{
|
|
g_Rect4DHash->RemoveRect (*iter2);
|
|
g_Rect4DHash->VerifyRectGone (*iter2);
|
|
delete *iter2;
|
|
}
|
|
m_LockedRects.clear ();
|
|
|
|
if (m_PathBlocked)
|
|
return;
|
|
|
|
if ((!quitting) && (!fromram))
|
|
ClearRamLock ();
|
|
stlport::vector<LockData *>::iterator iter;
|
|
|
|
for (iter = m_PathLock.begin ();iter != m_PathLock.end ();iter++)
|
|
{
|
|
if (!quitting)
|
|
{
|
|
MW4AI::g_MissionGraph->PassableLocalOverride ((*iter)->locx,(*iter)->locz,(*iter)->olddata);
|
|
MW4AI::RemoveBlockLocal ((*iter)->locx,(*iter)->locz,(MWObject *) this);
|
|
}
|
|
delete (*iter);
|
|
}
|
|
m_PathLock.clear ();
|
|
|
|
}
|
|
|
|
bool MoverAI::AddLockCell (const Stuff::Point3D& loc)
|
|
{
|
|
Check_Object (this);
|
|
unsigned short value;
|
|
int locx,locz;
|
|
Point3D pt;
|
|
|
|
if ((m_BoardingDropShip != DROP_NOT_ACTIVE) && (m_BoardingDropShip != DROP_FIRST_POINT))
|
|
return false; // ignore all collisions when trying to board dropship
|
|
|
|
if (loc.x < MW4AI::MinX)
|
|
return true;
|
|
if (loc.z < MW4AI::MinX)
|
|
return true;
|
|
if (loc.x >= MW4AI::MaxX)
|
|
return true;
|
|
if (loc.z >= MW4AI::MaxZ)
|
|
return true;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
locx = (int) (loc.x);
|
|
locz = (int) (loc.z);
|
|
// locx = Truncate_Float_To_Word(loc.x);
|
|
// locz = Truncate_Float_To_Word(loc.z);
|
|
locx /= BLOCK_GRID_RES;
|
|
locz /= BLOCK_GRID_RES;
|
|
|
|
MWObject *who;
|
|
|
|
who = MW4AI::BlockerLocal (locx,locz);
|
|
if (who == (MWObject *) this)
|
|
return true;
|
|
if (who)
|
|
return false;
|
|
|
|
value = MW4AI::g_MissionGraph->PassableLocal (locx,locz);
|
|
if (value & (MOVEPASSNOW_FLAG))
|
|
return false;
|
|
|
|
MW4AI::g_MissionGraph->PassableLocalOverride (locx,locz,(unsigned short)(value|MOVEPASSNOW_FLAG));
|
|
if (MW4AI::AddBlockLocal (locx,locz,(MWObject *) this))
|
|
m_PathLock.push_back (new LockData (locx,locz,value));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MoverAI::CheckSquare (const Point3D& loc,Stuff::Scalar rad,int dir,int mask,bool tenmeter)
|
|
{
|
|
Check_Object (this);
|
|
int sqrindex[9][2] = {
|
|
{-1,-1},
|
|
{0,-1},
|
|
{1,-1},
|
|
{-1,0},
|
|
{1,0},
|
|
{-1,1},
|
|
{0,1},
|
|
{1,1},
|
|
{0,0}
|
|
};
|
|
int cx,cz,sx,sz;
|
|
|
|
sx = (int) loc.x/10;
|
|
sz = (int) loc.z/10;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
tenmeter = true;
|
|
if (tenmeter)
|
|
{
|
|
cx = sx+sqrindex[8][0];
|
|
cz = sz+sqrindex[8][1];
|
|
|
|
if (!(BlockerLocal (cx,cz) == (MWObject *)this))
|
|
if (!g_MissionGraph->MoveTo (cx,cz,dir,mask))
|
|
return false;
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
int i;
|
|
for (i=0;i<9;i++)
|
|
{
|
|
cx = sx+sqrindex[i][0];
|
|
cz = sz+sqrindex[i][1];
|
|
|
|
if (BlockerLocal (cx,cz) == (MWObject *)this)
|
|
continue;
|
|
|
|
if (!g_MissionGraph->MoveTo (cx,cz,dir,mask))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool MoverAI::LockSquare (const Point3D& loc,Stuff::Scalar rad,Point3D& culprit)
|
|
{
|
|
Check_Object (this);
|
|
int sqrindex[8][2] = {
|
|
{-1,-1},
|
|
{0,-1},
|
|
{1,-1},
|
|
{-1,0},
|
|
{1,0},
|
|
{-1,1},
|
|
{0,1},
|
|
{1,1}
|
|
};
|
|
int i;
|
|
Point3D pt (0,0,0);
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
for (i=0;i<8;i++)
|
|
{
|
|
pt.x = loc.x+(sqrindex[i][0]*rad);
|
|
pt.z = loc.z+(sqrindex[i][1]*rad);
|
|
|
|
if (LockedByMe (pt))
|
|
continue;
|
|
|
|
if (!AddLockCell (pt))
|
|
{
|
|
culprit = pt;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool MoverAI::AddLockRect (Rect4D *newrect,bool carecollide,Stuff::Time till)
|
|
{
|
|
Verify (false);
|
|
delete newrect;
|
|
#if 0
|
|
Check_Object (this);
|
|
Rect4D *crect;
|
|
Point3D loc;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
|
|
if ((m_BoardingDropShip != DROP_NOT_ACTIVE) && (m_BoardingDropShip != DROP_FIRST_POINT))
|
|
return false; // ignore all collisions when trying to board dropship
|
|
|
|
if ((m_PathBlocked))
|
|
{
|
|
g_Rect4DHash->AddRect (newrect);
|
|
m_LockedRects.push_back (newrect);
|
|
return true;
|
|
}
|
|
if (!carecollide)
|
|
{
|
|
g_Rect4DHash->AddRect (newrect);
|
|
m_LockedRects.push_back (newrect);
|
|
return false;
|
|
}
|
|
crect = g_Rect4DHash->Collide (*newrect);
|
|
if (crect)
|
|
{
|
|
Verify (m_Vehicle);
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
UnitVector3D p1,p2;
|
|
Point3D extra,otherloc;
|
|
if (m_OrderSpeed < 0)
|
|
m_Vehicle->GetLocalToWorld ().GetLocalBackwardInWorld (&p1);
|
|
else
|
|
m_Vehicle->GetLocalToWorld ().GetLocalForwardInWorld (&p1);
|
|
Scalar dot = 5.0f;
|
|
if (EqualRamTarget (crect->who))
|
|
{
|
|
dot = -5.0f;
|
|
// ignore ram target
|
|
}
|
|
else if ((crect->who) && (crect->who->IsDerivedFrom (AI::DefaultData)))
|
|
{
|
|
dot = 1.0f;
|
|
#if 0
|
|
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.1f;
|
|
else
|
|
{
|
|
p2 = extra;
|
|
dot = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if ((crect->who) && (crect->who->IsDerivedFrom (MWPlayer::DefaultData)))
|
|
{
|
|
dot = 1.0f;
|
|
#if 0
|
|
MWPlayer *player;
|
|
player = (MWPlayer *) crect->who;
|
|
if (player->vehicle)
|
|
{
|
|
otherloc = (Point3D) player->vehicle->GetLocalToWorld ();
|
|
extra.Subtract (otherloc,loc);
|
|
if (Small_Enough (extra.GetLength ()))
|
|
dot = 0.0f;
|
|
else
|
|
{
|
|
p2 = extra; // normalizes
|
|
dot = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if ((crect->who) && (crect->who->IsDerivedFrom (Building::DefaultData)))
|
|
{
|
|
dot = -1.0f;
|
|
}
|
|
if (dot > 0)
|
|
{
|
|
HandleObstacle (crect);
|
|
delete newrect;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
g_Rect4DHash->AddRect (newrect);
|
|
m_LockedRects.push_back (newrect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_Rect4DHash->AddRect (newrect);
|
|
m_LockedRects.push_back (newrect);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void MoverAI::ClearTempLockRects (void)
|
|
{
|
|
stlport::vector<Rect4D *>::iterator iter;
|
|
|
|
for (iter = m_TempLockRects.begin ();iter != m_TempLockRects.end ();iter++)
|
|
{
|
|
delete (*iter);
|
|
}
|
|
m_TempLockRects.clear ();
|
|
}
|
|
|
|
void MoverAI::CalcTempLock (void)
|
|
{
|
|
Check_Object (this);
|
|
|
|
stlport::vector<Rect4D *>::iterator iter;
|
|
|
|
for (iter = m_TempLockRects.begin ();iter != m_TempLockRects.end ();iter++)
|
|
{
|
|
Verify ((*iter));
|
|
int sx,sy;
|
|
int ex,ey;
|
|
int cx,cy;
|
|
|
|
sx = (int) (*iter)->left;
|
|
sy = (int) (*iter)->top;
|
|
ex = (int) (*iter)->right;
|
|
ey = (int) (*iter)->bottom;
|
|
sx /= BLOCK_GRID_RES;
|
|
sy /= BLOCK_GRID_RES;
|
|
ex /= BLOCK_GRID_RES;
|
|
ey /= BLOCK_GRID_RES;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
|
|
// m_TempLock.clear ();
|
|
|
|
for (cx = sx;cx <= ex;cx++)
|
|
{
|
|
for (cy = sy;cy<= ey;cy++)
|
|
{
|
|
unsigned short value;
|
|
Point3D pt;
|
|
|
|
if (cx < MW4AI::MinX)
|
|
continue;
|
|
if (cy < MW4AI::MinZ)
|
|
continue;
|
|
if (cx >= MW4AI::MaxX)
|
|
continue;
|
|
if (cy >= MW4AI::MaxZ)
|
|
continue;
|
|
|
|
value = MW4AI::g_MissionGraph->PassableLocal (cx,cy);
|
|
|
|
MW4AI::g_MissionGraph->PassableLocalOverride (cx,cy,(unsigned short)(value|MOVEPASSNOW_FLAG));
|
|
m_TempLock.push_back (new LockData (cx,cy,value));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MoverAI::CalcUnTempLock (void)
|
|
{
|
|
Check_Object (this);
|
|
stlport::vector<LockData *>::iterator iter;
|
|
|
|
ClearTempLockRects ();
|
|
|
|
if (m_TempLock.size () == 0)
|
|
return;
|
|
for (iter = m_TempLock.end ()-1;iter != m_TempLock.begin ();iter--)
|
|
{
|
|
MW4AI::g_MissionGraph->PassableLocalOverride ((*iter)->locx,(*iter)->locz,(*iter)->olddata);
|
|
delete (*iter);
|
|
}
|
|
m_TempLock.clear ();
|
|
}
|
|
|
|
void MoverAI::CalcPathLock (CPathRequest *req)
|
|
{
|
|
if (req)
|
|
{
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
Point3D end;
|
|
CRailPath *node;
|
|
CGridPath *grid;
|
|
node = req->NodePath ();
|
|
grid = req->GridPath ();
|
|
if (node)
|
|
{
|
|
end = node->End();
|
|
}
|
|
else if (grid)
|
|
{
|
|
end = grid->End();
|
|
}
|
|
req->UpdateSrcDest (loc,end);
|
|
}
|
|
CalcTempLock ();
|
|
if ((m_PathBlockedRect) && (m_PathBlockedRect->who))
|
|
{
|
|
|
|
Stuff::Point3D extra;
|
|
float sx,sy,dx,dy;
|
|
int ix,iy,ex,ey;
|
|
int count;
|
|
int startx,starty,endx,endy;
|
|
|
|
extra = (Point3D) m_PathBlockedRect->who->GetLocalToWorld ();
|
|
startx = (int) extra.x;
|
|
starty = (int) extra.z;
|
|
endx = (int) (((m_PathBlockedRect->right-m_PathBlockedRect->left)/2.0f) + m_PathBlockedRect->left);
|
|
endy = (int) (((m_PathBlockedRect->bottom-m_PathBlockedRect->top)/2.0f) + m_PathBlockedRect->top);
|
|
startx /= BLOCK_GRID_RES;
|
|
starty /= BLOCK_GRID_RES;
|
|
endx /= BLOCK_GRID_RES;
|
|
endy /= BLOCK_GRID_RES;
|
|
if (startx == endx)
|
|
endx = startx+1;
|
|
if (starty == endy)
|
|
endy = starty+1;
|
|
dx = (float) endx - startx;
|
|
dy = (float) endy - starty;
|
|
if (dx == 0)
|
|
dx = 1;
|
|
if (dy == 0)
|
|
dy = 1;
|
|
sx = dx < 0 ? dx*-1.0f : dx;
|
|
sy = dy < 0 ? dy*-1.0f : dy;
|
|
|
|
if (sx > sy)
|
|
{
|
|
dy = dy / sx;
|
|
count = (int) (dx<0.0 ? dx*-1.0f : dx);
|
|
dx = dx<0 ? -1.0f : 1.0f;
|
|
}
|
|
else
|
|
{
|
|
dx = dx / sy;
|
|
count = (int) (dy<0.0 ? dy*-1.0f : dy);
|
|
dy = dy<0 ? -1.0f : 1.0f;
|
|
}
|
|
|
|
sx = (float) startx;
|
|
sy = (float) starty;
|
|
ex = endx;
|
|
ey = endy;
|
|
ix = (int) (sx);
|
|
iy = (int) (sy);
|
|
while (count)
|
|
{
|
|
count--;
|
|
sx += dx;
|
|
sy += dy;
|
|
ix = (int) (sx);
|
|
iy = (int) (sy);
|
|
unsigned short value;
|
|
|
|
value = MW4AI::g_MissionGraph->PassableLocal (ix,iy);
|
|
if (value & MOVEPASSNOW_FLAG)
|
|
continue;
|
|
MW4AI::g_MissionGraph->PassableLocalOverride (ix,iy,(unsigned short)(value|MOVEPASSNOW_FLAG));
|
|
m_TempLock.push_back (new LockData (ix,iy,value));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void MoverAI::CalcPathUnlock (CPathRequest *reg)
|
|
{
|
|
Check_Object (this);
|
|
stlport::vector<LockData*>::iterator iter;
|
|
for (iter = m_TempLock.begin ();iter != m_TempLock.end ();iter++)
|
|
{
|
|
MW4AI::g_MissionGraph->PassableLocalOverride ((*iter)->locx,(*iter)->locz,(*iter)->olddata);
|
|
}
|
|
CalcUnTempLock ();
|
|
}
|
|
|
|
bool MoverAI::PathLock (bool secondpass,bool fromram)
|
|
{
|
|
if (g_AlwaysIgnoreObstacles == true)
|
|
return (false);
|
|
if (m_EnteringFieldBase != FIELDBASE_NOT_ACTIVE)
|
|
return false;
|
|
|
|
Check_Object (this);
|
|
if (!m_Vehicle)
|
|
return false;
|
|
|
|
MOVER_LOGIC("PathLock");
|
|
#if !defined(NO_TIMERS)
|
|
my_AutoTimer fred ((void *) &tDynamicObstacleTime);
|
|
#endif
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
Check_Object (m_Vehicle);
|
|
Check_Object (m_Vehicle->GetGameModel ());
|
|
|
|
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = m_Vehicle->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = m_Vehicle->GetSolidVolume ();
|
|
Stuff::Scalar rad = 10.0f;
|
|
if (!col)
|
|
return false;
|
|
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, m_Vehicle->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
if (!obb)
|
|
return false;
|
|
ExtentBox box (*obb);
|
|
|
|
rad = obb->sphereRadius;
|
|
rad *= 2.0f;
|
|
|
|
Stuff::Scalar speed,movemps,slowtime;
|
|
UnitVector3D forward;
|
|
Point3D step,loc;
|
|
int i,timelen;
|
|
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
if (m_OrderSpeed < 0)
|
|
m_Vehicle->GetLocalToWorld ().GetLocalBackwardInWorld (&forward);
|
|
else
|
|
m_Vehicle->GetLocalToWorld ().GetLocalForwardInWorld (&forward);
|
|
step = forward;
|
|
|
|
LockSquare (loc,rad,m_PathBlockedCell);
|
|
AddLockCell (loc);
|
|
|
|
if (m_CheapMover)
|
|
return false;
|
|
|
|
speed = m_Vehicle->currentSpeedMPS;
|
|
if ((m_Vehicle->speedDemand == 0) || (m_ObstacleRequest))
|
|
{
|
|
MOVER_LOGIC("PathLock 2");
|
|
if ((m_OrderSpeed == 0) || (m_ObstacleRequest))
|
|
{
|
|
m_PathBlocked = false;
|
|
delete m_PathBlockedRect;
|
|
m_PathBlockedRect = NULL;
|
|
}
|
|
if (!fromram)
|
|
RamLock ();
|
|
return false;
|
|
}
|
|
|
|
if (speed < 0)
|
|
{
|
|
movemps = -speed;
|
|
Max_Clamp(movemps, -model->maxReverseSpeed);
|
|
Min_Clamp(movemps, -model->minReverseSpeed);
|
|
slowtime = movemps / (model->decceleration*model->reverseDeccelerationMultiplier);
|
|
}
|
|
else
|
|
{
|
|
movemps = speed;
|
|
Max_Clamp(movemps, model->maxSpeed);
|
|
Min_Clamp(movemps, model->minSpeed);
|
|
slowtime = movemps / model->decceleration;
|
|
}
|
|
Min_Clamp (movemps,1);
|
|
step *= movemps;
|
|
|
|
slowtime += 1.0f; //extra second of buffer
|
|
timelen = (int) (slowtime);
|
|
|
|
int maxi;
|
|
int mask;
|
|
bool tenmeter = AllowTenMeter ();
|
|
Scalar delta;
|
|
delta = 10.0f/movemps;
|
|
step *= delta;
|
|
|
|
maxi = (int) (timelen / delta);
|
|
|
|
mask = MW4AI::ConvertTypetoUsage (model->moveTypeFlag);
|
|
mask = MW4AI::ConvertUsagetoMovePass (mask);
|
|
Min_Clamp (maxi,1);
|
|
loc += step;
|
|
{
|
|
MOVER_LOGIC("PathLock 3");
|
|
for (i=0;i<maxi;i++)
|
|
{
|
|
if ((!secondpass) && (!fromram))
|
|
{
|
|
if (!CheckSquare (loc,rad,0,mask,tenmeter))
|
|
{
|
|
ClearPathLock (false,false);
|
|
PathLock (true,false);
|
|
RecalcPath (gos_GetElapsedTime ());
|
|
if (!fromram)
|
|
RamLock ();
|
|
return false;
|
|
}
|
|
loc += step;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_PathBlocked = false;
|
|
|
|
if (!fromram)
|
|
RamLock ();
|
|
return false;
|
|
}
|
|
void MoverAI::SetRamTarget (MWObject *obj)
|
|
{
|
|
Check_Object (this);
|
|
m_RamTarget = obj;
|
|
}
|
|
void MoverAI::ClearRamLock (void)
|
|
{
|
|
Check_Object (this);
|
|
if (m_RamTarget)
|
|
{
|
|
MoverAI *ai = NULL;
|
|
MWObject *playervehicle;
|
|
if (MWPlayer::GetInstance())
|
|
{
|
|
Entity *tent;
|
|
tent = MWPlayer::GetInstance()->vehicle;
|
|
playervehicle = Cast_Object (MWObject *,tent);
|
|
}
|
|
else
|
|
playervehicle = NULL;
|
|
|
|
if (m_RamTarget->IsDerivedFrom (MoverAI::DefaultData))
|
|
{
|
|
ai = (MoverAI *) m_RamTarget;
|
|
}
|
|
else if (m_RamTarget->GetAI ())
|
|
{
|
|
AI *tempai;
|
|
tempai = m_RamTarget->GetAI ();
|
|
if (tempai->IsDerivedFrom (MoverAI::DefaultData))
|
|
ai = (MoverAI *) tempai;
|
|
}
|
|
if ((m_RamTarget == playervehicle) && (MWPlayer::GetInstance()))
|
|
((MWPlayer *) MWPlayer::GetInstance())->ClearPathLock (false);
|
|
else if (ai)
|
|
ai->ClearPathLock (false,true);
|
|
}
|
|
}
|
|
|
|
void MoverAI::RamLock (void)
|
|
{
|
|
Check_Object (this);
|
|
if (m_RamTarget)
|
|
{
|
|
MoverAI *ai = NULL;
|
|
MWObject *playervehicle;
|
|
if (MWPlayer::GetInstance())
|
|
{
|
|
Entity *tent;
|
|
tent = MWPlayer::GetInstance()->vehicle;
|
|
playervehicle = Cast_Object (MWObject *,tent);
|
|
}
|
|
else
|
|
playervehicle = NULL;
|
|
|
|
if (m_RamTarget->IsDerivedFrom (MoverAI::DefaultData))
|
|
{
|
|
ai = (MoverAI *) m_RamTarget;
|
|
}
|
|
else if (m_RamTarget->GetAI ())
|
|
{
|
|
AI *tempai;
|
|
tempai = m_RamTarget->GetAI ();
|
|
if (tempai->IsDerivedFrom (MoverAI::DefaultData))
|
|
ai = (MoverAI *) tempai;
|
|
}
|
|
if ((m_RamTarget == playervehicle) && (MWPlayer::GetInstance()))
|
|
((MWPlayer *) MWPlayer::GetInstance())->PathLock ();
|
|
else if (ai)
|
|
ai->PathLock (false,true);
|
|
}
|
|
}
|
|
|
|
void MoverAI::RecalcPath (Stuff::Time till)
|
|
{
|
|
Check_Object (this);
|
|
Verify (m_Vehicle);
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
if (m_CurPath)
|
|
{
|
|
if (m_FailCount > MAX_FAILS_PATROL)
|
|
{
|
|
m_FailCount = 0;
|
|
if ((m_CurMove) && ((m_CurMove->MoveType () == MOVE_PATROL) || (m_CurMove->MoveType () == MOVE_SEMIPATROL)))
|
|
{
|
|
if (m_CurMove->MoveType () == MOVE_SEMIPATROL)
|
|
{
|
|
CSemiPatrolData *pat;
|
|
pat = (CSemiPatrolData *) m_CurMove;
|
|
if (pat->CurRequest () < (pat->RequestSize ()-1))
|
|
{
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
m_CurMove->PathDone (this,till,false);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CPatrolData *pat;
|
|
pat = (CPatrolData *) m_CurMove;
|
|
if (pat->CurRequest () < (pat->RequestSize ()-1))
|
|
{
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
m_CurMove->PathDone (this,till,false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_FailCount++;
|
|
Point3D loc,end,outvec;
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
end = m_CurPath->End ();
|
|
|
|
if (m_ObstacleRequest)
|
|
{
|
|
if (!m_ObstacleRequest->Done ())
|
|
{
|
|
if (!m_ObstacleRequest->UpdateSrcDest (loc,end))
|
|
{
|
|
g_PathManager->RemoveRequest (m_ObstacleRequest);
|
|
delete m_ObstacleRequest;
|
|
m_ObstacleRequest = NULL;
|
|
}
|
|
else
|
|
{
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Point3D pathend;
|
|
Scalar dist,dx,dz;
|
|
pathend = m_ObstacleRequest->GetEndPoint ();
|
|
dx = pathend.x - end.x;
|
|
dz = pathend.z - end.z;
|
|
dist = (dx*dx) + (dz*dz);
|
|
if (dist > 400.0f) // new end is > 20 meters to this point so recalc
|
|
{
|
|
g_PathManager->RemoveRequest (m_ObstacleRequest);
|
|
delete m_ObstacleRequest;
|
|
m_ObstacleRequest = NULL;
|
|
}
|
|
else
|
|
{
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
const Vehicle__GameModel *model = static_cast<const MechWarrior4::Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
gos_PushCurrentHeap (g_RailHeap);
|
|
|
|
Verify (m_CurMove);
|
|
|
|
m_ObstacleRequest = g_PathManager->AddRequest (gos_GetElapsedTime (),MW4AI::g_MissionGraph,loc,end,MW4AI::ConvertTypetoUsage (model->moveTypeFlag),this,AllowTenMeter ());
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
gos_PopCurrentHeap ();
|
|
}
|
|
else
|
|
{
|
|
if (m_CurMove && (m_CurMove->MoveType () == MOVE_SEMIPATROL))
|
|
{
|
|
CSemiPatrolData *pat;
|
|
pat = (CSemiPatrolData *) m_CurMove;
|
|
Point3D loc;
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
if (m_ObstacleRequest)
|
|
{
|
|
pat->UpdatePathRequest (loc,m_ObstacleRequest);
|
|
}
|
|
else
|
|
{
|
|
const Vehicle__GameModel *model = static_cast<const MechWarrior4::Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
m_ObstacleRequest = pat->NeedPathRequest (loc,MW4AI::ConvertTypetoUsage (model->moveTypeFlag));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MoverAI::ExecuteMoveHeadCollision (Stuff::Time till)
|
|
{
|
|
Check_Object (this);
|
|
Verify (m_PathBlocked);
|
|
Verify (m_Vehicle);
|
|
CommandEntry *com;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
|
|
if (m_MoveHead != Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
com = CreateTurnToCommand (m_MoveHead,m_OrderSpeed < 0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
else
|
|
{
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
if (m_Vehicle->speedDemand != 0)
|
|
{
|
|
com = CreateSetSpeedCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
Verify (m_PathBlockedRect);
|
|
if (m_PathBlockedRect)
|
|
{
|
|
m_PathBlockedRect->time = (int) ((float) (till * Rect4DTimeDelta));
|
|
m_PathBlockedRect->time += m_PathBlockedRectTimeDelta;
|
|
Rect4D *crect;
|
|
crect = g_Rect4DHash->Collide (*m_PathBlockedRect);
|
|
Scalar dot = -5.0f;
|
|
if (crect)
|
|
{
|
|
Point3D loc;
|
|
UnitVector3D p1,p2;
|
|
Point3D extra,otherloc;
|
|
if (m_OrderSpeed < 0)
|
|
m_Vehicle->GetLocalToWorld ().GetLocalBackwardInWorld (&p1);
|
|
else
|
|
m_Vehicle->GetLocalToWorld ().GetLocalForwardInWorld (&p1);
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
if ((crect->who) && (crect->who->IsDerivedFrom (AI::DefaultData)))
|
|
{
|
|
dot = 1.0f;
|
|
#if 0
|
|
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; // normalizes
|
|
dot = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if ((crect->who) && (crect->who->IsDerivedFrom (MWPlayer::DefaultData)))
|
|
{
|
|
dot = 1.0f;
|
|
#if 0
|
|
MWPlayer *player;
|
|
player = (MWPlayer *) crect->who;
|
|
if (player->vehicle)
|
|
{
|
|
otherloc = (Point3D) player->vehicle->GetLocalToWorld ();
|
|
extra.Subtract (otherloc,loc);
|
|
if (Small_Enough (extra.GetLength ()))
|
|
dot = 0.0f;
|
|
else
|
|
{
|
|
p2 = extra; // normalizes
|
|
dot = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
if (dot >= 0)
|
|
{
|
|
if (gos_GetElapsedTime () > m_LockTime)
|
|
{
|
|
if (!((m_CurMove) && (m_CurMove->MoveType () == MOVE_RIGIDPATROL)))
|
|
{
|
|
m_PathBlocked = false;
|
|
// m_ObstacleAvoidMode = false;
|
|
ClearPathLock (false,false);
|
|
RecalcPath (till);
|
|
delete m_PathBlockedRect;
|
|
m_PathBlockedRect = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_PathBlocked = false;
|
|
// m_ObstacleAvoidMode = false;
|
|
delete m_PathBlockedRect;
|
|
m_PathBlockedRect = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MoverAI::ObstacleNearBy (const Point3D& loc)
|
|
{
|
|
return false;
|
|
/*
|
|
if (g_AlwaysIgnoreObstacles == true)
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
int x,y;
|
|
int count;
|
|
|
|
x = (int) (loc.x / MACROBLOCK_GRID_RES);
|
|
y = (int) (loc.z / MACROBLOCK_GRID_RES);
|
|
count = 0;
|
|
count = g_MissionGraph->MacroPassable (loc.x,loc.z);
|
|
return (count != 0);
|
|
*/
|
|
}
|
|
|
|
void MoverAI::ExecuteMoveHead (Stuff::Time till)
|
|
{
|
|
Check_Object (this);
|
|
if (!m_Vehicle)
|
|
return;
|
|
|
|
bool m_SpeedHitSlow = false;
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
if (m_Jumping)
|
|
Jump (till,m_MoveHead);
|
|
if (m_NewMoveHead != m_MoveHead)
|
|
{
|
|
if (m_Jumping)
|
|
{
|
|
m_BurnTime = -1.0f;
|
|
Jump (till,m_MoveHead);
|
|
}
|
|
if (m_MoveHead != Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
m_OldMoveHead = m_MoveHead;
|
|
ConstructRect (m_OldMoveHead,m_NewMoveHead,5.0f);
|
|
}
|
|
else
|
|
{
|
|
m_OldMoveHead = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
ConstructRect (m_OldMoveHead,m_NewMoveHead,5.0f);
|
|
}
|
|
m_MoveHead = m_NewMoveHead;
|
|
m_NeedHeadingAdjust = true;
|
|
}
|
|
if (m_NewOutVec != m_OutVec)
|
|
{
|
|
m_OutVec = m_NewOutVec;
|
|
}
|
|
if (m_ObstacleRequest)
|
|
{
|
|
m_NewSpeedRequest = m_NewEndSpeedRequest = 0;
|
|
m_MoveHead = Point3D (-1,-1,-1);
|
|
}
|
|
m_EndSpeedRequest = m_NewEndSpeedRequest;
|
|
if (m_NewSpeedRequest != m_Vehicle->speedDemand)
|
|
{
|
|
m_SpeedRequest = m_NewSpeedRequest;
|
|
m_NeedSpeedAdjust = true;
|
|
}
|
|
if (m_JumpRequested)
|
|
{
|
|
Verify (!m_Jumping);
|
|
Jump (till,m_MoveHead);
|
|
}
|
|
|
|
|
|
Point3D loc(0,0,0);
|
|
CommandEntry *com;
|
|
Stuff::Scalar speed;
|
|
|
|
// CheckObstacle (till);
|
|
|
|
if (m_PathBlocked)
|
|
{
|
|
ExecuteMoveHeadCollision (till);
|
|
return;
|
|
}
|
|
|
|
if (m_MoveHead == Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
m_NeedHeadingAdjust = false;
|
|
m_SpeedRequest = 0;
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateSetSpeedCommand (m_SpeedRequest);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
return;
|
|
}
|
|
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
|
|
Point3D realheadpoint;
|
|
if (((m_BoardingDropShip == DROP_NOT_ACTIVE) || ((m_BoardingDropShip == DROP_FIRST_POINT))) && (m_EnteringFieldBase == FIELDBASE_NOT_ACTIVE))
|
|
{
|
|
switch (HeadPointInRect (m_Vehicle->GetLocalToWorld (),m_Vehicle->currentSpeedMPS,GetTimeSlice (till)))
|
|
{
|
|
case LEFT_INSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
// realheadpoint = RightHeadPoint (loc,m_MoveHead);
|
|
// m_SpeedHitSlow = true;
|
|
break;
|
|
case RIGHT_INSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
// realheadpoint = LeftHeadPoint (loc,m_MoveHead);
|
|
// m_SpeedHitSlow = true;
|
|
break;
|
|
case TOP_INSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
break;
|
|
case BOTTOM_INSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
break;
|
|
case LEFT_OUTSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
// realheadpoint = RightHeadPoint (loc,m_MoveHead);
|
|
// m_SpeedHitSlow = true;
|
|
break;
|
|
case RIGHT_OUTSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
// realheadpoint = LeftHeadPoint (loc,m_MoveHead);
|
|
// m_SpeedHitSlow = true;
|
|
break;
|
|
case TOP_OUTSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
break;
|
|
case BOTTOM_OUTSIDE_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
break;
|
|
case NO_HIT:
|
|
realheadpoint = m_MoveHead;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
realheadpoint = m_MoveHead;
|
|
}
|
|
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
speed = m_Vehicle->speedDemand;
|
|
loc.y = 0;
|
|
|
|
Verify (realheadpoint != Stuff::Point3D (-1,-1,-1));
|
|
Scalar timeturn;
|
|
Point3D a,b;
|
|
Scalar dist,movemps,heading_adjustment,absadjust;
|
|
Point3D distance_to_target;
|
|
|
|
LinearMatrix4D tempmat (m_Vehicle->GetLocalToWorld ());
|
|
tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis);
|
|
distance_to_target.MultiplyByInverse(realheadpoint,tempmat);
|
|
if ((m_OrderSpeed < 0) || (m_SpeedRequest < 0)) // reverse direction
|
|
{
|
|
distance_to_target.x = -distance_to_target.x;
|
|
distance_to_target.z = -distance_to_target.z;
|
|
}
|
|
if (Small_Enough(distance_to_target.z) && Small_Enough(distance_to_target.x))
|
|
distance_to_target.z = 1.0f;
|
|
heading_adjustment = Arctan(distance_to_target.x, distance_to_target.z);
|
|
absadjust = heading_adjustment<0?-1.0f*heading_adjustment:heading_adjustment;
|
|
|
|
a.Subtract (loc,realheadpoint);
|
|
dist = a.GetLength ();
|
|
|
|
if ((absadjust > 0.05f))
|
|
{
|
|
m_NeedHeadingAdjust = true;
|
|
if (ObstacleNearBy (loc))
|
|
{
|
|
if (absadjust > 0.05f)
|
|
{
|
|
m_SpeedRequest = 0;
|
|
m_NeedSpeedAdjust = true;
|
|
}
|
|
}
|
|
|
|
if (absadjust > Pi_Over_4)
|
|
{
|
|
m_SpeedRequest = 0;
|
|
m_NeedSpeedAdjust = true;
|
|
}
|
|
}
|
|
if ((m_OrderSpeed >= 0) && (m_SpeedRequest >= 0))
|
|
{
|
|
Stuff::Scalar slowtime,slowdist,slowspeed;
|
|
if (m_OutVec == Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
slowspeed = m_EndSpeedRequest;
|
|
}
|
|
else
|
|
{
|
|
LinearMatrix4D tempmat (m_Vehicle->GetLocalToWorld ());
|
|
tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis);
|
|
distance_to_target.MultiplyByInverse(m_OutVec,tempmat);
|
|
if (m_OrderSpeed < 0) // reverse direction
|
|
{
|
|
distance_to_target.x = -distance_to_target.x;
|
|
distance_to_target.z = -distance_to_target.z;
|
|
}
|
|
if (Small_Enough(distance_to_target.z) && Small_Enough(distance_to_target.x))
|
|
distance_to_target.z = 1.0f;
|
|
heading_adjustment = Arctan(distance_to_target.x, distance_to_target.z);
|
|
timeturn = heading_adjustment / model->fullStopTurnRate;
|
|
timeturn = timeturn<0 ? timeturn*-1.0f : timeturn;
|
|
if (Small_Enough (timeturn))
|
|
slowspeed = 0;
|
|
else
|
|
slowspeed = 10.0f/timeturn;
|
|
}
|
|
|
|
// if (m_OutVec == Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
movemps = m_Vehicle->currentSpeedMPS;
|
|
movemps = movemps<0 ? movemps*-1.0f : movemps;
|
|
if (movemps > slowspeed)
|
|
{
|
|
movemps -= slowspeed;
|
|
if (speed < 0)
|
|
{
|
|
slowtime = movemps / (model->decceleration*model->reverseDeccelerationMultiplier);
|
|
slowdist = (0.5f * (model->decceleration*model->reverseDeccelerationMultiplier) * (slowtime*slowtime)) + (movemps*slowtime);
|
|
}
|
|
else
|
|
{
|
|
slowtime = movemps / model->decceleration;
|
|
slowdist = (0.5f * model->decceleration * (slowtime*slowtime)) + (movemps*slowtime);
|
|
}
|
|
a.Subtract (loc,realheadpoint);
|
|
dist = a.GetLength ();
|
|
if (m_OldMoveHead != Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
Stuff::Scalar olddist;
|
|
b.Subtract (loc,m_OldMoveHead);
|
|
olddist = b.GetLength ();
|
|
if (olddist < dist)
|
|
dist = olddist;
|
|
}
|
|
|
|
if (dist <= slowdist)
|
|
{
|
|
Scalar temp;
|
|
temp = dist - (0.5f * model->decceleration * (slowtime*slowtime));
|
|
movemps = temp / slowtime;
|
|
if (movemps < 0)
|
|
movemps = 0;
|
|
|
|
speed = ((movemps) - (float) model->minSpeed) / ((float) model->maxSpeed - (float) model->minSpeed);
|
|
if (speed < m_SpeedRequest)
|
|
{
|
|
m_SpeedRequest = speed;
|
|
m_NeedSpeedAdjust = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (m_NeedSpeedAdjust)
|
|
{
|
|
if (m_SpeedHitSlow)
|
|
{
|
|
Scalar fred;
|
|
fred = m_SpeedRequest/2.0f;
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ());
|
|
if (fred > 0)
|
|
{
|
|
if (fred < model->minSpeed / model->maxSpeed)
|
|
{
|
|
if (m_Vehicle->IsDerivedFrom (Mech::DefaultData))
|
|
{
|
|
Mech *mech;
|
|
mech = Cast_Object (Mech *,m_Vehicle);
|
|
fred = (model->minSpeed+1.0f) / mech->GetMaxSpeed ();
|
|
}
|
|
else
|
|
{
|
|
fred = (model->minSpeed+1.0f) / model->maxSpeed;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((fred != 0) &&
|
|
(fred > -model->minReverseSpeed / model->maxReverseSpeed))
|
|
{
|
|
fred = -model->minReverseSpeed / model->maxReverseSpeed;
|
|
}
|
|
}
|
|
|
|
com = CreateSetSpeedCommand (fred);
|
|
}
|
|
else
|
|
com = CreateSetSpeedCommand (m_SpeedRequest);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
m_NeedSpeedAdjust = false;
|
|
}
|
|
|
|
m_NeedHeadingAdjust = false;
|
|
com = CreateTurnToCommand (realheadpoint,(m_OrderSpeed < 0) || (m_SpeedRequest<0));
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
void MoverAI::SetOrderSpeed (Stuff::Scalar newvalue)
|
|
{
|
|
m_OrderSpeed = newvalue;
|
|
}
|
|
|
|
bool MoverAI::RequestJump (Stuff::Time till)
|
|
{
|
|
if (!m_AIJumpAllowed)
|
|
return false;
|
|
if (m_OrderSpeed < 0)
|
|
return false;
|
|
if (!m_CurPath)
|
|
return false;
|
|
if (!m_CurPath->Calced ())
|
|
return false;
|
|
if (m_CurPath->JumpSoon ())
|
|
return false;
|
|
|
|
return Jump (till,m_MoveHead,true);
|
|
}
|
|
|
|
bool MoverAI::Jump (Stuff::Time till,const Stuff::Point3D& dest,bool request)
|
|
{
|
|
Verify (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Mech::DefaultData));
|
|
Verify (m_Vehicle->GetGameModel ()->moveTypeFlag == MechWarrior4::MWObject__GameModel::LEGJUMP_MOVETYPE);
|
|
if (m_Jumping)
|
|
{
|
|
if ((till - m_StartJump) >= m_BurnTime)
|
|
{
|
|
Mech *mech;
|
|
mech = Cast_Object (Mech *,m_Vehicle);
|
|
mech->StopJumpRequest();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Mech *mech;
|
|
int forcespeed=0;
|
|
JumpJet *jumpjet;
|
|
Stuff::Scalar dist;
|
|
Point3D extra,loc(m_Vehicle->GetLocalToWorld ());
|
|
extra.Subtract (dest,loc);
|
|
dist = extra.GetLength ();
|
|
mech = Cast_Object (Mech *,m_Vehicle);
|
|
jumpjet = mech->GetJumpJet ();
|
|
if (!jumpjet)
|
|
{
|
|
#if defined(LAB_ONLY)
|
|
PAUSE (("tried to jump with no jump jet"));
|
|
#endif
|
|
if (request)
|
|
return false;
|
|
if (m_CurPath)
|
|
{
|
|
CRailLink *link;
|
|
int linkid;
|
|
|
|
linkid = m_CurPath->CurLink ();
|
|
if (linkid != -1)
|
|
{
|
|
link = g_MissionGraph->Link (linkid);
|
|
if (link)
|
|
{
|
|
link->Weight (-1.0f,JUMPINDEX,link->Location (0));
|
|
link->Weight (-1.0f,JUMPINDEX,link->Location (1));
|
|
link->Jump (false,link->Location (0));
|
|
link->Jump (false,link->Location (1));
|
|
}
|
|
}
|
|
}
|
|
if ((m_CurMove) && (m_CurMove->MoveType () == MOVE_RIGIDPATROL))
|
|
m_CurMove->Done (true);
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Check_Object (jumpjet);
|
|
m_BurnTime = jumpjet->CalcBurnTime (dist,dest.y - loc.y,mech->currentSpeedMPS);
|
|
if (m_BurnTime > jumpjet->CurrentCharge ())
|
|
{
|
|
m_BurnTime = jumpjet->CalcBurnTime (dist,dest.y - loc.y,mech->currentSpeedMPS+5.0f);
|
|
if (m_BurnTime > jumpjet->CurrentCharge ())
|
|
{
|
|
if (request)
|
|
return false;
|
|
m_BurnTime = jumpjet->CalcBurnTime (dist,dest.y - loc.y,m_Vehicle->GetGameModel ()->maxSpeed);
|
|
if (m_BurnTime > jumpjet->CurrentCharge ())
|
|
{
|
|
if (m_CurPath)
|
|
{
|
|
CRailLink *link;
|
|
int linkid;
|
|
|
|
linkid = m_CurPath->CurLink ();
|
|
if (linkid != -1)
|
|
{
|
|
link = g_MissionGraph->Link (linkid);
|
|
if (link)
|
|
{
|
|
link->Weight (-1.0f,JUMPINDEX,link->Location (0));
|
|
link->Weight (-1.0f,JUMPINDEX,link->Location (1));
|
|
link->Jump (false,link->Location (0));
|
|
link->Jump (false,link->Location (1));
|
|
}
|
|
}
|
|
}
|
|
if ((m_CurMove) && (m_CurMove->MoveType () == MOVE_RIGIDPATROL))
|
|
m_CurMove->Done (true);
|
|
RecalcPath(gos_GetElapsedTime ());
|
|
return false;
|
|
}
|
|
else
|
|
forcespeed = 2;
|
|
}
|
|
else
|
|
forcespeed = 1;
|
|
}
|
|
}
|
|
Point3D distance_to_target;
|
|
YawPitchRoll rot(m_Vehicle->GetLocalToWorld ());
|
|
|
|
LinearMatrix4D tempmat (m_Vehicle->GetLocalToWorld ());
|
|
tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis);
|
|
|
|
distance_to_target.MultiplyByInverse(dest, tempmat);
|
|
|
|
Scalar heading_adjustment = Arctan(distance_to_target.x, distance_to_target.z);
|
|
if ((heading_adjustment > Pi_Over_8) || (heading_adjustment < -Pi_Over_8))
|
|
{
|
|
if (request)
|
|
return false;
|
|
}
|
|
if (mech->JumpRequest())
|
|
{
|
|
m_Jumping = true;
|
|
m_JumpRequested = false;
|
|
m_StartJump = till;
|
|
|
|
if (forcespeed)
|
|
{
|
|
mech->m_ForceSpeed = true;
|
|
if (forcespeed == 1)
|
|
mech->m_ForceSpeedValue = mech->currentSpeedMPS + 5.0f;
|
|
else
|
|
mech->m_ForceSpeedValue = m_Vehicle->GetGameModel ()->maxSpeed;
|
|
}
|
|
mech->m_ForceYaw = true;
|
|
mech->m_ForceYawValue = rot.yaw + heading_adjustment;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MoverAI::TurnOn (void)
|
|
{
|
|
delete m_CheapMover;
|
|
m_CheapMover = NULL;
|
|
inherited::TurnOn ();
|
|
}
|
|
|
|
void MoverAI::TurnOff (void)
|
|
{
|
|
Verify (!m_CheapMover);
|
|
inherited::TurnOff ();
|
|
if (m_Vehicle)
|
|
{
|
|
m_CheapMover = new CCheapMover ((Point3D) m_Vehicle->GetLocalToWorld ());
|
|
}
|
|
}
|
|
|
|
void MoverAI::ExecutePath (Stuff::Time till)
|
|
{
|
|
Check_Object (this);
|
|
if (!m_CurPath)
|
|
return;
|
|
gosREPORT (m_Vehicle,"somehow a mover ai got a path when no vehicle is attached to it");
|
|
bool jump=false,prejump=false;
|
|
|
|
Point3D loc(0,0,0),head(0,0,0);
|
|
Stuff::Point3D outvec (-1,-1,-1);
|
|
|
|
Verify (m_CurMove);
|
|
Verify (m_CurMove->Executing ());
|
|
|
|
if (m_PathBad)
|
|
{
|
|
if (gos_GetElapsedTime () >= m_RecalcTime)
|
|
{
|
|
RecalcPath (till);
|
|
m_PathBlocked = false;
|
|
m_PathBad = false;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
if (!m_CurPath) // could be killed from recalcpath
|
|
return;
|
|
if (!m_CurPath->Calced ())
|
|
{
|
|
NotifyNoPath ();
|
|
PathDone (till,true);
|
|
return;
|
|
}
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
|
|
CRailPath::PATHSTATES state;
|
|
state = m_CurPath->State ();
|
|
|
|
__int64 subtime = GetCycles ();
|
|
{
|
|
Scalar cursp;
|
|
if (m_CheapMover)
|
|
cursp = m_SpeedRequest*model->maxSpeed*0.9f;
|
|
else
|
|
cursp = m_Vehicle->currentSpeedMPS;
|
|
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
|
|
loc.y = 0;
|
|
m_CurPath->Tick (loc,GetTimeSlice (till),cursp,outvec,jump,prejump);
|
|
subtime = GetCycles () - subtime;
|
|
}
|
|
if (m_CurPath->State () == CRailPath::RAIL_MOVE_WAITING)
|
|
{
|
|
SetMoveHead (Stuff::Point3D (-1,-1,-1),0);
|
|
return;
|
|
}
|
|
|
|
if (!m_CurPath->Calced ())
|
|
{
|
|
NotifyNoPath ();
|
|
PathDone (till,true);
|
|
return;
|
|
}
|
|
|
|
m_FailCount = 0;
|
|
head = m_CurPath->Heading ();
|
|
if (jump)
|
|
Jump (till,head);
|
|
else
|
|
m_Jumping = false;
|
|
|
|
if (m_CurMove)
|
|
{
|
|
if (m_CurMove->MoveType () == MOVE_PATROL)
|
|
{
|
|
if (outvec == Point3D (-1,-1,-1))
|
|
{
|
|
CPatrolData *fred = (CPatrolData *) m_CurMove;
|
|
if (fred->CurRequest () < (fred->RequestSize ()-1))
|
|
{
|
|
outvec = fred->Location (fred->CurRequest ()+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_CurPath->State () != CRailPath::RAIL_FINISH)
|
|
{
|
|
// if ((prejump) || (jump))
|
|
// SetMoveHead (head,1.0f,outvec);
|
|
// else
|
|
SetMoveHead (head,m_OrderSpeed,outvec);
|
|
}
|
|
else
|
|
{
|
|
Verify (m_CurMove);
|
|
Verify (m_CurMove->Executing ());
|
|
NewPath (NULL);
|
|
PathDone (till,false);
|
|
}
|
|
}
|
|
|
|
void MoverAI::ExecuteMoveCommand (Stuff::Time till)
|
|
{
|
|
Check_Object (this);
|
|
if (!m_CurMove)
|
|
return;
|
|
gosREPORT (((m_CurMove->MoveType () == MOVE_LOOKOUT) || (m_Vehicle) ),"somehow a moverai got a move command when no vehicle is attached to it");
|
|
|
|
if (m_CurMove->Done ())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!m_CurMove->Executing ())
|
|
{
|
|
m_CurMove->StartExecuting (this,till);
|
|
SetOrderSpeed (m_CurMove->Speed ());
|
|
}
|
|
else
|
|
{
|
|
m_CurMove->Execute (this,till);
|
|
SetOrderSpeed (m_CurMove->Speed ());
|
|
}
|
|
}
|
|
|
|
void MoverAI::NewPath (CRailPath *path,bool overridemove)
|
|
{
|
|
Check_Object (this);
|
|
if (overridemove)
|
|
{
|
|
ClearMoveOrder ();
|
|
}
|
|
delete m_CurPath;
|
|
m_CurPath = path;
|
|
if (m_ObstacleRequest)
|
|
{
|
|
g_PathManager->RemoveRequest (m_ObstacleRequest);
|
|
delete m_ObstacleRequest;
|
|
m_ObstacleRequest = NULL;
|
|
}
|
|
|
|
if ((m_CurPath == NULL) && (m_CurMove==NULL))
|
|
{
|
|
CommandEntry *com;
|
|
com = CreateTurnCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateSetSpeedCommand (0.0f);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
SetMoveHead (Stuff::Point3D (-1,-1,-1),0);
|
|
SetOrderSpeed (0);
|
|
return;
|
|
}
|
|
if (m_CurPath == NULL)
|
|
return;
|
|
|
|
Verify (m_CurMove);
|
|
Verify (m_CurMove->Executing ());
|
|
|
|
Stuff::Point3D outvec,loc;
|
|
|
|
Verify (m_Vehicle);
|
|
loc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
loc.y = 0;
|
|
if (m_CurMove)
|
|
{
|
|
SetOrderSpeed (m_CurMove->Speed ());
|
|
}
|
|
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Scalar cursp;
|
|
if (m_CheapMover)
|
|
cursp = m_SpeedRequest*model->maxSpeed*0.9f;
|
|
else
|
|
cursp = m_Vehicle->currentSpeedMPS;
|
|
|
|
bool jump,prejump;
|
|
if (m_CurPath->Calced ())
|
|
m_CurPath->Tick (m_CurPath->Start (),GetTimeSlice (gos_GetElapsedTime ()),cursp,outvec,jump,prejump);
|
|
if (m_CurPath->Calced ())
|
|
m_CurPath->Tick (loc,GetTimeSlice (gos_GetElapsedTime ()),cursp,outvec,jump,prejump);
|
|
|
|
if (!m_CurPath->Calced ())
|
|
{
|
|
SetMoveHead (Stuff::Point3D (-1,-1,-1),0);
|
|
CommandEntry *com;
|
|
com = CreateSetSpeedCommand (0.0f);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
else
|
|
{
|
|
if (m_CurPath->State () != CRailPath::RAIL_MOVE_WAITING)
|
|
m_FailCount = 0;
|
|
m_PathBlocked = false;
|
|
m_PathBad = false;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MoverAI::Die (void)
|
|
{
|
|
Check_Object (this);
|
|
inherited::Die ();
|
|
ClearMoveOrder ();
|
|
ClearPathLock (false,false);
|
|
#if 0
|
|
if (m_Vehicle)
|
|
{
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = m_Vehicle->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = m_Vehicle->GetSolidVolume ();
|
|
|
|
if (col)
|
|
{
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, who->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
ExtentBox box (*obb);
|
|
int x,z;
|
|
int minx,maxx,minz,maxz;
|
|
|
|
minx = (int) box.minX;
|
|
maxx = (int) box.maxX;
|
|
minz = (int) box.minZ;
|
|
maxz = (int) box.maxZ;
|
|
minx /= BLOCK_GRID_RES;
|
|
maxx /= BLOCK_GRID_RES;
|
|
minz /= BLOCK_GRID_RES;
|
|
maxz /= BLOCK_GRID_RES;
|
|
if (minx < (MinX/10.0f))
|
|
minx = (MinX/10.0f);
|
|
if (minz < (MinZ/10.0f))
|
|
minz = (MinZ/10.0f);
|
|
if (maxx >= (MaxX/10.0f))
|
|
maxx = (int) (MaxX/10)-1;
|
|
if (maxz >= (MaxZ/10.0f))
|
|
maxz = (int) (MaxZ/10)-1;
|
|
|
|
for (x=minx;x<=maxx;x++)
|
|
{
|
|
for (z=minz;z<=maxz;z++)
|
|
{
|
|
MW4AI::g_MissionGraph->PassableLocal (x,z,BLOCKED_FLAGS);
|
|
}
|
|
}
|
|
Rect4D temprect;
|
|
temprect.left = box.minX;
|
|
temprect.right = box.maxX;
|
|
temprect.top = box.minY;
|
|
temprect.bottom = box.maxY;
|
|
temprect.who = NULL;
|
|
g_Rect4DHash->AddPermRect (temprect);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void MoverAI::PreCollisionExecute(Time till)
|
|
{
|
|
extern int g_nMR;
|
|
if (g_nMR == 2)
|
|
return;
|
|
|
|
Check_Object(this);
|
|
AI_LOGIC("Pre-Collision::MoverAI");
|
|
#if defined(LAB_ONLY)
|
|
if (!instanceName)
|
|
MWGameInfo::g_LastMWObject[0] = '\0';
|
|
else
|
|
{
|
|
strncpy(MWGameInfo::g_LastMWObject, instanceName, sizeof(MWGameInfo::g_LastMWObject)-1);
|
|
MWGameInfo::g_LastMWObject[sizeof(MWGameInfo::g_LastMWObject)-1] = '\0';
|
|
}
|
|
MWGameInfo::g_LastMWObjectPos = GetLocalToWorld();
|
|
#endif
|
|
|
|
#if !defined(NO_TIMERS)
|
|
my_AutoTimer fred ((void *) &tMoverAITime);
|
|
#endif
|
|
|
|
//
|
|
//---------------------------------
|
|
// Verify that this always executes
|
|
//---------------------------------
|
|
//
|
|
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
Check_Object(executionState);
|
|
Verify(executionState->GetState() != ExecutionStateEngine::NeverExecuteState);
|
|
|
|
if (!ShouldRun (true))
|
|
{
|
|
ExecutePostPath (till);
|
|
if ((m_PathBad) || (m_CurPath && !m_CurPath->Calced ()) || (m_CurMove && m_CurMove->Speed () == 0))
|
|
{
|
|
CommandEntry *com;
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateTurnCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateSetSpeedCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
ABL::CurMoverAI = this;
|
|
AI::PreCollisionExecute (till);
|
|
ABL::CurMoverAI = NULL;
|
|
return;
|
|
}
|
|
|
|
ClearPathLock (false,false);
|
|
|
|
if (m_ObstacleRequest)
|
|
{
|
|
if (m_ObstacleRequest->Done ())
|
|
{
|
|
CRailPath *path;
|
|
path = m_ObstacleRequest->DetachNodePath ();
|
|
Check_Pointer (path);
|
|
delete m_ObstacleRequest;
|
|
m_ObstacleRequest = NULL;
|
|
NewPath (path);
|
|
}
|
|
}
|
|
|
|
if (m_OldMoveHead == Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
if (m_Vehicle)
|
|
m_OldMoveHead = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
}
|
|
|
|
ExecuteMoveCommand (till);
|
|
ExecutePath (till);
|
|
ExecutePostPath (till);
|
|
|
|
|
|
PathLock (false,false);
|
|
if ((m_PathBad) || (m_CurPath && !m_CurPath->Calced ()) || (m_CurMove && m_CurMove->Speed () == 0))
|
|
{
|
|
CommandEntry *com;
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateTurnCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
com = CreateSetSpeedCommand (0);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
ABL::CurMoverAI = this;
|
|
AI::PreCollisionExecute(till);
|
|
ABL::CurMoverAI = NULL;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MoverAI::DebugTextMessageHandler(Adept::ReceiverDataMessageOf<int> *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == DebugTextMessageID);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MoverAI::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
void MoverAI::ExecutePostPath (Stuff::Time till)
|
|
{
|
|
if (m_BoardingDropShip != DROP_NOT_ACTIVE)
|
|
{
|
|
CheckDropBoard (GetTimeSlice (till));
|
|
ExecuteMoveHead (till);
|
|
}
|
|
else if (m_EnteringFieldBase != FIELDBASE_NOT_ACTIVE)
|
|
{
|
|
CheckFieldBase (GetTimeSlice (till));
|
|
ExecuteMoveHead (till);
|
|
}
|
|
else if (m_Deactive)
|
|
{
|
|
if (m_CheapMover)
|
|
{
|
|
Check_Object (m_Vehicle);
|
|
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (m_MoveHead != Stuff::Point3D (-1,-1,-1))
|
|
{
|
|
m_OldMoveHead = m_MoveHead;
|
|
ConstructRect (m_OldMoveHead,m_NewMoveHead,5.0f);
|
|
}
|
|
else
|
|
{
|
|
m_OldMoveHead = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
ConstructRect (m_OldMoveHead,m_NewMoveHead,5.0f);
|
|
}
|
|
m_MoveHead = m_NewMoveHead;
|
|
|
|
m_SpeedRequest = m_NewSpeedRequest;
|
|
if (m_MoveHead != Point3D (-1,-1,-1))
|
|
{
|
|
m_CheapMover->UpdatePos (m_MoveHead,m_SpeedRequest*model->maxSpeed*0.9f,GetTimeSlice (till)); // fudge to slow down for turns and slopes
|
|
m_CheapMover->UpdatePos (m_Vehicle,m_MoveHead);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_Vehicle)
|
|
m_CheapMover = new CCheapMover ((Point3D) m_Vehicle->GetLocalToWorld ());
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
ExecuteMoveHead (till);
|
|
}
|
|
}
|
|
|
|
void MoverAI::ExecuteMoveCommand (MW4AI::CommandEntry *command)
|
|
{
|
|
Check_Object (this);
|
|
Check_Pointer (command);
|
|
|
|
ClearMoveOrder ();
|
|
Verify (!m_ObstacleRequest);
|
|
|
|
m_CurMove = (CMoveData *) command->DataPtr ();
|
|
gosREPORT (((m_CurMove->MoveType () == MOVE_LOOKOUT) || (m_Vehicle)),"cannot give a move command to a moverai with no vehicle");
|
|
const MWObject__GameModel *model = static_cast<const MechWarrior4::MWObject__GameModel *> (m_MWObject->GetGameModel ()) ;
|
|
|
|
Stuff::Point3D temp;
|
|
temp = (Stuff::Point3D) m_MWObject->GetLocalToWorld ();
|
|
temp.y = 0;
|
|
if (m_Vehicle)
|
|
m_CurMove->CreateRequests (temp,MW4AI::ConvertTypetoUsage (model->moveTypeFlag));
|
|
SetOrderSpeed (m_CurMove->Speed ());
|
|
|
|
Check_Pointer (m_CurMove);
|
|
}
|
|
|
|
void MoverAI::ClearMoveOrder (void)
|
|
{
|
|
Check_Object (this);
|
|
CommandEntry *com;
|
|
|
|
m_PathBad = false;
|
|
delete m_CurMove;
|
|
m_CurMove = NULL;
|
|
delete m_CurPath;
|
|
m_CurPath = NULL;
|
|
delete m_ObstacleRequest;
|
|
m_ObstacleRequest = NULL;
|
|
|
|
m_MoveHead = Stuff::Point3D (-1,-1,-1);
|
|
m_OutVec = Stuff::Point3D (-1,-1,-1);
|
|
m_NewMoveHead = Stuff::Point3D (-1,-1,-1);
|
|
m_NewOutVec = Stuff::Point3D (-1,-1,-1);
|
|
m_OldMoveHead = Stuff::Point3D (-1,-1,-1);
|
|
SetOrderSpeed (0);
|
|
SetMoveHead (m_MoveHead,0);
|
|
|
|
if (m_Vehicle)
|
|
{
|
|
com = CreateSetSpeedCommand (0.0f);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
com = CreateTurnCommand (0.0f);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
com = CreateKillTurnToCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
if (m_MWObject)
|
|
{
|
|
com = CreateKillTrackCommand ();
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
}
|
|
|
|
void MoverAI::ExecuteHighCommand (MW4AI::CommandEntry *command)
|
|
{
|
|
Check_Object (this);
|
|
Check_Pointer (command);
|
|
switch (command->Type ())
|
|
{
|
|
case MOVE_HIGHID:
|
|
ExecuteMoveCommand (command);
|
|
break;
|
|
case TELEPORT_HIGHID:
|
|
break;
|
|
case FLEE_HIGHID:
|
|
break;
|
|
case FORMONSPOT_HIGHID:
|
|
break;
|
|
case FOLLOW_HIGHID:
|
|
break;
|
|
default:
|
|
inherited::ExecuteHighCommand (command);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MoverAI::ExecuteLowCommand (MW4AI::CommandEntry *command)
|
|
{
|
|
Check_Object (this);
|
|
Check_Pointer (command);
|
|
switch (command->Type ())
|
|
{
|
|
case MOVETO_LOWID:
|
|
break;
|
|
case TURNTO_LOWID:
|
|
// gosREPORT (m_Vehicle,"cannot give a turnto command to a moverai with no vehicle");
|
|
if (m_Vehicle)
|
|
{
|
|
m_Vehicle->dirRequest = command->DataPoint3D ();
|
|
m_Vehicle->followDirRequest = true;
|
|
m_Vehicle->followDirRequestReverse = command->DataBoolean ();
|
|
}
|
|
break;
|
|
case TRACK_LOWID:
|
|
// gosREPORT (m_MWObject,"cannot give a track command to a moverai with no mwobject");
|
|
if ((m_MWObject) &&
|
|
(m_MWObject->GetTorso()))
|
|
{
|
|
gosREPORT (m_MWObject->GetTorso (),"cannot give a track command to a moverai that is attached to an object with no torso");
|
|
m_MWObject->GetTorso()->torsoRequest = command->DataPoint3D ();
|
|
m_MWObject->GetTorso()->followTorsoRequest = true;
|
|
}
|
|
break;
|
|
case TRACKTO_LOWID:
|
|
// gosREPORT (m_MWObject,"cannot give a trackto command to a moverai with no mwobject");
|
|
if (m_MWObject)
|
|
{
|
|
Torso *torso;
|
|
|
|
torso = m_MWObject->GetTorso ();
|
|
gosREPORT (torso,"cannot give a trackto command to a moverai with no mwobject with no torso");
|
|
torso->yawDemand = command->DataScalar();
|
|
}
|
|
break;
|
|
case KILLTURNTO_LOWID:
|
|
// gosREPORT (m_Vehicle,"cannot give a killturnto command to a moverai with no vehicle");
|
|
if (m_Vehicle)
|
|
m_Vehicle->followDirRequest = false;
|
|
break;
|
|
case KILLTRACK_LOWID:
|
|
// gosREPORT (m_MWObject,"cannot give a killtrack command to a moverai with no mwobject");
|
|
if ((m_MWObject) &&
|
|
(m_MWObject->GetTorso()))
|
|
m_MWObject->GetTorso()->followTorsoRequest = false;
|
|
break;
|
|
case TURN_LOWID:
|
|
// gosREPORT (m_Vehicle,"cannot give a turn command to a moverai with no vehicle");
|
|
if (m_Vehicle)
|
|
m_Vehicle->yawDemand = command->DataScalar ();
|
|
break;
|
|
case SETSPEED_LOWID:
|
|
{
|
|
// gosREPORT (m_Vehicle,"cannot give a setspeed command to a moverai with no vehicle");
|
|
Verify (command->DataScalar () >=-1.0f);
|
|
Verify (command->DataScalar () <= 1.0f);
|
|
|
|
Stuff::Scalar speed = command->DataScalar();
|
|
if ((speed > 0) &&
|
|
(speed < GetMinSpeed()))
|
|
{
|
|
speed = GetMinSpeed();
|
|
}
|
|
|
|
if (m_Vehicle)
|
|
{
|
|
if (m_PathBlocked)
|
|
m_Vehicle->speedDemand = 0; // to protect against a flood of collision requests, or just walking off the map
|
|
else if ((m_CurPath) && ((!m_CurPath->Calced ()) || (m_CurPath->State () == CRailPath::RAIL_MOVE_WAITING)))
|
|
m_Vehicle->speedDemand = 0; // to protect against a flood of collision requests, or just walking off the map
|
|
else
|
|
m_Vehicle->speedDemand = speed;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
inherited::ExecuteHighCommand (command);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void MoverAI::orderMoveLookOut (void)
|
|
{
|
|
Check_Object (this);
|
|
if (!m_Active)
|
|
return;
|
|
CLookoutData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_LOOKOUT)
|
|
return;
|
|
|
|
if (m_MWObject->GetTorso() == 0)
|
|
{
|
|
ClearMoveOrder();
|
|
return;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CLookoutData (MW4AI::g_MissionGraph,this);
|
|
|
|
newmove->ClearEnd (false);
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
bool MoverAI::orderMoveTo (Path *path,int speed,int type,bool forwards,bool clear)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a moveto order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CPatrolData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
float normalspeed;
|
|
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove = (CPatrolData *) m_CurMove;
|
|
Check_Object (path);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_PATROL)
|
|
if (newmove->PathID () == path->objectID)
|
|
{
|
|
m_CurMove->Speed (normalspeed);
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CPatrolData (MW4AI::g_MissionGraph,this);
|
|
newmove->SetupPath (path);
|
|
|
|
newmove->Speed (normalspeed);
|
|
newmove->PatrolType ((Patrol_Type) type);
|
|
newmove->ClearEnd (clear);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MoverAI::orderMoveToSemi (Path *path,int speed,int type,bool forwards,bool clear)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a moveto order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CSemiPatrolData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
float normalspeed;
|
|
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove = (CSemiPatrolData *) m_CurMove;
|
|
Check_Object (path);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_SEMIPATROL)
|
|
if (newmove->PathID () == path->objectID)
|
|
{
|
|
m_CurMove->Speed (normalspeed);
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CSemiPatrolData (MW4AI::g_MissionGraph,this);
|
|
newmove->SetupPath (path);
|
|
|
|
newmove->Speed (normalspeed);
|
|
newmove->PatrolType ((Patrol_Type) type);
|
|
newmove->ClearEnd (clear);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MoverAI::orderMoveToRigid (Path *path,int speed,int type,bool forwards,bool clear)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a moveto order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CRigidPatrolData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
newmove = (CRigidPatrolData *) m_CurMove;
|
|
Check_Object (path);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_RIGIDPATROL)
|
|
if (newmove->PathID () == path->objectID)
|
|
{
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CRigidPatrolData (MW4AI::g_MissionGraph,this);
|
|
newmove->SetupPath (path);
|
|
|
|
float normalspeed;
|
|
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->Speed (normalspeed);
|
|
newmove->PatrolType ((Patrol_Type) type);
|
|
newmove->ClearEnd (clear);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
int MoverAI::orderMoveFlee (Entity *away,int speed)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a flee order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return INT_MAX;
|
|
CFleeData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
float normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove = (CFleeData *) m_CurMove;
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_FLEE)
|
|
if (!newmove->Done ())
|
|
if (newmove->FleeFrom ()->objectID == away->objectID)
|
|
if (m_CurMove->Speed () == normalspeed)
|
|
return newmove->FleeDistance (m_Vehicle);
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CFleeData (MW4AI::g_MissionGraph,this);
|
|
|
|
|
|
newmove->ClearEnd (false);
|
|
newmove->InsertObject (away);
|
|
newmove->Speed (normalspeed);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return newmove->FleeDistance (m_Vehicle);
|
|
}
|
|
bool MoverAI::orderMoveResumePatrol (Path *path,int speed,int type,bool forwards,bool clear) // todo fix this to start at the closest point
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a resume patrol order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CPatrolData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
newmove = (CPatrolData *) m_CurMove;
|
|
Check_Object (path);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_PATROL)
|
|
if (newmove->PathID () == path->objectID)
|
|
{
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CPatrolData (MW4AI::g_MissionGraph,this);
|
|
newmove->SetupPath (path);
|
|
|
|
float normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->Speed (normalspeed);
|
|
newmove->PatrolType ((Patrol_Type) type);
|
|
newmove->ClearEnd (clear);
|
|
|
|
newmove->StartPathAt (path->GetNearestIndex ((Stuff::Point3D) m_Vehicle->GetLocalToWorld ()));
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MoverAI::orderMoveResumePatrolSemi (Path *path,int speed,int type,bool forwards,bool clear) // todo fix this to start at the closest point
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a resume patrol order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CSemiPatrolData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
newmove = (CSemiPatrolData *) m_CurMove;
|
|
Check_Object (path);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_SEMIPATROL)
|
|
if (newmove->PathID () == path->objectID)
|
|
{
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CSemiPatrolData (MW4AI::g_MissionGraph,this);
|
|
newmove->SetupPath (path);
|
|
|
|
float normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->Speed (normalspeed);
|
|
newmove->PatrolType ((Patrol_Type) type);
|
|
newmove->ClearEnd (clear);
|
|
|
|
newmove->StartPathAt (path->GetNearestIndex ((Stuff::Point3D) m_Vehicle->GetLocalToWorld ()));
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MoverAI::orderMoveResumePatrolRigid (Path *path,int speed,int type,bool forwards,bool clear) // todo fix this to start at the closest point
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a resume patrol order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CRigidPatrolData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
newmove = (CRigidPatrolData *) m_CurMove;
|
|
Check_Object (path);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_RIGIDPATROL)
|
|
if (newmove->PathID () == path->objectID)
|
|
{
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CRigidPatrolData (MW4AI::g_MissionGraph,this);
|
|
newmove->SetupPath (path);
|
|
|
|
float normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->Speed (normalspeed);
|
|
newmove->PatrolType ((Patrol_Type) type);
|
|
newmove->ClearEnd (clear);
|
|
|
|
newmove->StartPathAt (path->GetNearestIndex ((Stuff::Point3D) m_Vehicle->GetLocalToWorld ()));
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
|
|
void MoverAI::orderMoveFollow (Entity *who,int offsetx,int offsetz,int maxspeed)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a follow order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return;
|
|
int id;
|
|
|
|
if (who->IsDerivedFrom (AI::DefaultData))
|
|
{
|
|
AI *ai;
|
|
|
|
ai = Cast_Object (AI *,who);
|
|
Verify (ai->getEntity ());
|
|
id = ai->getEntity ()->objectID;
|
|
}
|
|
else
|
|
{
|
|
id = who->objectID;
|
|
}
|
|
CFollowData *newmove;
|
|
newmove = (CFollowData *) m_CurMove;
|
|
MW4AI::CommandEntry *com;
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_FOLLOW)
|
|
if (newmove->Follow ()->objectID == id)
|
|
if (newmove->FollowXOffset () == offsetx)
|
|
if (newmove->FollowZOffset () == offsetz)
|
|
return;
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CFollowData (MW4AI::g_MissionGraph,this);
|
|
|
|
newmove->ClearEnd (false);
|
|
newmove->InsertObject (who);
|
|
newmove->FollowXOffset ((Stuff::Scalar) offsetx);
|
|
newmove->FollowZOffset ((Stuff::Scalar) offsetz);
|
|
|
|
Scalar normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (maxspeed > 0)
|
|
normalspeed = ((float) maxspeed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = 0.25f;
|
|
|
|
if (normalspeed < 0.25f)
|
|
normalspeed = 0.25f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->MaxSpeed (normalspeed);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
void MoverAI::orderMoveSit (bool shutdown)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a sit order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return;
|
|
CSitData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_SIT)
|
|
{
|
|
return;
|
|
}
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CSitData (MW4AI::g_MissionGraph,this);
|
|
|
|
newmove->ClearEnd (false);
|
|
if (shutdown)
|
|
Shutdown ();
|
|
else
|
|
Startup ();
|
|
|
|
ClearMoveOrder ();
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
}
|
|
|
|
bool MoverAI::orderMoveToLocPoint (const Stuff::Point3D& where,int speed,bool forwards,bool clear)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a movetoloc order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CMoveLocPointData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
Point3D comppt;
|
|
|
|
comppt = where;
|
|
|
|
ConvertPointToGrid (comppt);
|
|
newmove = (CMoveLocPointData *) m_CurMove;
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_LOCPOINT)
|
|
if (newmove->LocPoint () == comppt)
|
|
{
|
|
if (m_CurMove->Done ())
|
|
{
|
|
if (m_CurMove->ClearEnd ())
|
|
ClearMoveOrder ();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CMoveLocPointData (MW4AI::g_MissionGraph,this);
|
|
|
|
float normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->InsertPoint (where);
|
|
newmove->Speed (normalspeed);
|
|
newmove->ClearEnd (clear);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
bool MoverAI::orderMoveToObject (Entity *what,int speed)
|
|
{
|
|
Check_Object (this);
|
|
gosREPORT (m_Vehicle,"cannot give a movetoobject order to a moverai with no vehicle attached to it");
|
|
if (!m_Active)
|
|
return false;
|
|
CMoveObjectData *newmove;
|
|
MW4AI::CommandEntry *com;
|
|
|
|
newmove = (CMoveObjectData *) m_CurMove;
|
|
Check_Object (what);
|
|
if (m_CurMove)
|
|
if (m_CurMove->MoveType () == MOVE_OBJECT)
|
|
if (newmove->TargetObject ()->objectID == what->objectID)
|
|
{
|
|
return m_CurMove->Done ();
|
|
}
|
|
|
|
AutoHeap local_heap (g_MoverAIHeap);
|
|
newmove = new CMoveObjectData (MW4AI::g_MissionGraph,this);
|
|
|
|
float normalspeed;
|
|
|
|
Check_Object (m_Vehicle);
|
|
Verify (m_Vehicle->IsDerivedFrom (Vehicle::DefaultData));
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
if (speed > 0)
|
|
normalspeed = ((float) speed) / ((float) model->maxSpeed);
|
|
else
|
|
normalspeed = -((float) speed) / ((float) model->maxReverseSpeed);
|
|
|
|
if (normalspeed < -1.0f)
|
|
normalspeed = -1.0f;
|
|
if (normalspeed > 1.0f)
|
|
normalspeed = 1.0f;
|
|
|
|
newmove->InsertObject (what);
|
|
newmove->Speed (normalspeed);
|
|
newmove->ClearEnd (false);
|
|
|
|
m_TimeNotMoving = 0;
|
|
|
|
com = CreateMoveCommand (newmove);
|
|
Check_Pointer (com);
|
|
ExecuteCommand (com);
|
|
|
|
return false;
|
|
}
|
|
|
|
void MoverAI::Info (void (*printCallback)(char* s))
|
|
{
|
|
Check_Object (this);
|
|
char text[100];
|
|
|
|
inherited::Info (printCallback);
|
|
if (m_CurMove)
|
|
sprintf (text,"There is a current move order");
|
|
else
|
|
sprintf (text,"There is no current move order");
|
|
printCallback (text);
|
|
}
|
|
|
|
void MoverAI::NotifyRespawned()
|
|
{
|
|
ClearMoveOrder();
|
|
|
|
ClearPathLock (false,false);
|
|
delete m_PathBlockedRect;
|
|
if (m_CheapMover)
|
|
delete m_CheapMover;
|
|
ClearTempLockRects ();
|
|
m_CheapMover = NULL;
|
|
m_PathBlockedRect = NULL;
|
|
|
|
m_TimeNotMoving = 0;
|
|
m_CombatLeashRadius = 0;
|
|
m_CombatLeash.Zero();
|
|
AI::NotifyRespawned();
|
|
}
|
|
|
|
|
|
void MoverAI::ConstructRect (const Point3D& start,const Point3D& end,Stuff::Scalar width)
|
|
{
|
|
m_StartPoint = start;
|
|
m_EndPoint = end;
|
|
m_StartPoint.y = m_EndPoint.y = 0;
|
|
|
|
if (start == end)
|
|
{
|
|
m_TopLeft.x = start.x + 10.0f;
|
|
m_TopLeft.z = start.z + 10.0f;
|
|
m_TopRight.x = start.x + 10.0f;
|
|
m_TopRight.z = start.z + 10.0f;
|
|
m_BottomLeft.x = end.x + 10.0f;
|
|
m_BottomLeft.z = end.z + 10.0f;
|
|
m_BottomRight.x = end.x + 10.0f;
|
|
m_BottomRight.z = end.z + 10.0f;
|
|
return;
|
|
}
|
|
Point3D dir,left,right;
|
|
dir.Subtract (end,start);
|
|
dir.Normalize (dir);
|
|
left.x = -dir.z;
|
|
left.z = dir.x;
|
|
right.x = dir.z;
|
|
right.z = dir.x;
|
|
left *= (width/2.0f);
|
|
right *= (width/2.0f);
|
|
m_TopLeft.y = m_TopRight.y = m_BottomLeft.y = m_BottomRight.y = 0;
|
|
|
|
m_TopLeft.x = start.x + left.x;
|
|
m_TopLeft.z = start.z + left.z;
|
|
m_TopRight.x = start.x + right.x;
|
|
m_TopRight.z = start.z + right.z;
|
|
m_BottomLeft.x = end.x + left.x;
|
|
m_BottomLeft.z = end.z + left.z;
|
|
m_BottomRight.x = end.x + right.x;
|
|
m_BottomRight.z = end.z + right.z;
|
|
}
|
|
|
|
bool MoverAI::Intersect (const Point3D& start,const Point3D& end,const Point3D& p1,const Point3D& p2)
|
|
{
|
|
Scalar b1,b2,xi,m1,m2,t;
|
|
Scalar dx1,dx2;
|
|
|
|
dx1 = p2.x - p1.x;
|
|
dx2 = end.x - start.x;
|
|
if (dx1 == 0)
|
|
dx1 = 100000000.0f;
|
|
if (dx2 == 0)
|
|
dx2 = 100000000.0f;
|
|
m1 = ((p2.z-p1.z)/(dx1));
|
|
m2 = ((end.z-start.z)/(dx2));
|
|
b1 = p1.z - m1*p1.x;
|
|
b2 = start.z - m2*start.x;
|
|
|
|
if (m1 == m2)
|
|
xi = (b2-b1)/100000000.0f;
|
|
else
|
|
xi = (b2-b1)/(m1-m2);
|
|
t = (xi-start.x)/(dx2);
|
|
return ((t>=-0.02f) && (t<=1.02f));
|
|
}
|
|
|
|
Point3D MoverAI::LeftHeadPoint (const Point3D& loc,const Stuff::Point3D& head)
|
|
{
|
|
|
|
Point3D toret,dir;
|
|
UnitVector3D extra;
|
|
|
|
if (m_StartPoint == m_EndPoint)
|
|
return m_EndPoint;
|
|
dir.Subtract (m_EndPoint,m_StartPoint);
|
|
extra = dir;
|
|
Line3D line (m_StartPoint,extra,10000.0f);
|
|
line.GetClosestPointTo (loc,&toret);
|
|
dir = extra;
|
|
dir *= 10.0f;
|
|
toret += dir;
|
|
return toret;
|
|
}
|
|
|
|
Point3D MoverAI::RightHeadPoint (const Point3D& loc,const Stuff::Point3D& head)
|
|
{
|
|
|
|
Point3D toret,dir;
|
|
UnitVector3D extra;
|
|
|
|
if (m_StartPoint == m_EndPoint)
|
|
return m_EndPoint;
|
|
dir.Subtract (m_EndPoint,m_StartPoint);
|
|
extra = dir;
|
|
Line3D line (m_StartPoint,extra,10000.0f);
|
|
line.GetClosestPointTo (loc,&toret);
|
|
dir = extra;
|
|
dir *= 10.0f;
|
|
toret += dir;
|
|
return toret;
|
|
}
|
|
|
|
MoverAI::HeadHit MoverAI::HeadPointInRect (const LinearMatrix4D& loc,Scalar speed,Stuff::Scalar delta)
|
|
{
|
|
Point3D start(loc), end;
|
|
Point3D dir,inter;
|
|
UnitVector3D extra;
|
|
|
|
speed *= delta;
|
|
if (speed < 0)
|
|
{
|
|
loc.GetLocalBackwardInWorld (&extra);
|
|
speed = -speed;
|
|
}
|
|
else
|
|
{
|
|
loc.GetLocalForwardInWorld (&extra);
|
|
}
|
|
dir = extra;
|
|
dir *= speed;
|
|
end.Add (start,dir);
|
|
|
|
if (Intersect (start,end,m_TopLeft,m_BottomLeft))
|
|
return LEFT_INSIDE_HIT;
|
|
if (Intersect (start,end,m_TopRight,m_BottomRight))
|
|
return RIGHT_INSIDE_HIT;
|
|
if (Intersect (start,end,m_TopLeft,m_TopRight))
|
|
return TOP_INSIDE_HIT;
|
|
if (Intersect (start,end,m_BottomLeft,m_BottomRight))
|
|
return BOTTOM_INSIDE_HIT;
|
|
|
|
end = m_EndPoint;
|
|
if (Intersect (start,end,m_TopLeft,m_BottomLeft))
|
|
return LEFT_OUTSIDE_HIT;
|
|
if (Intersect (start,end,m_TopRight,m_BottomRight))
|
|
return RIGHT_OUTSIDE_HIT;
|
|
if (Intersect (start,end,m_TopLeft,m_TopRight))
|
|
return TOP_OUTSIDE_HIT;
|
|
if (Intersect (start,end,m_BottomLeft,m_BottomRight))
|
|
return BOTTOM_OUTSIDE_HIT;
|
|
return NO_HIT;
|
|
|
|
}
|
|
|
|
#if 0
|
|
Stuff::Point3D m_DropShipWait; // point to wait to board drop ship
|
|
Stuff::Point3D m_DropShipBoard; // point outside doors
|
|
Stuff::Point3D m_DropShipCenter; // point at center of dropship
|
|
Stuff::Point3D m_DropShipFinal; // final point to stand in drop ship
|
|
bool m_BoardingDropShip;
|
|
std::vector<MoverAI *> m_OtherDropShipBoarders;
|
|
int m_DropshipID; // which of the five we are
|
|
Dropship *m_DropShip;
|
|
#endif
|
|
|
|
void MoverAI::AddDropshipBoarder (int id,MoverAI *who)
|
|
{
|
|
Verify (id>=0);
|
|
Verify (id<5);
|
|
m_OtherDropShipBoarders[id] = who;
|
|
if (who == this)
|
|
m_DropShipID = id;
|
|
}
|
|
|
|
void MoverAI::CreateDropShipPoints (int id,Dropship *dropship)
|
|
{
|
|
Verify (m_OtherDropShipBoarders[id] == this);
|
|
Verify (m_DropShipID == id);
|
|
Check_Object (dropship);
|
|
m_DropShip = dropship;
|
|
m_DropShipCenter = (Point3D) dropship->GetLocalToWorld ();
|
|
m_DropShipID = id;
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = m_DropShip->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = m_DropShip->GetSolidVolume ();
|
|
Verify (col);
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, m_Vehicle->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
ExtentBox box (*obb);
|
|
|
|
Scalar dist = obb->sphereRadius;
|
|
m_DropShipWait = m_DropShipCenter;
|
|
m_DropShipBoard = m_DropShipCenter;
|
|
m_DropShipFinal = m_DropShipCenter;
|
|
switch (m_DropShipID)
|
|
{
|
|
case 0:
|
|
m_DropShipWait.z -= dist*BOARD_RADIUS;
|
|
m_DropShipWait.x -= dist*(BOARD_RADIUS);
|
|
m_DropShipBoard.z -= dist*BOARD_RADIUS;
|
|
m_DropShipFinal.z -= dist * 0.5f;
|
|
m_DropShipFinal.x -= dist * 0.25f;
|
|
break;
|
|
case 1:
|
|
m_DropShipWait.z += dist*BOARD_RADIUS;
|
|
m_DropShipWait.x -= dist*BOARD_RADIUS;
|
|
m_DropShipBoard.z += dist*BOARD_RADIUS;
|
|
m_DropShipFinal.z += dist * 0.5f;
|
|
m_DropShipFinal.x -= dist * 0.25f;
|
|
break;
|
|
case 2:
|
|
m_DropShipWait.z -= dist*BOARD_RADIUS;
|
|
m_DropShipWait.x += dist*BOARD_RADIUS;
|
|
m_DropShipBoard.z -= dist*BOARD_RADIUS;
|
|
m_DropShipFinal.z -= dist * 0.5f;
|
|
m_DropShipFinal.x += dist * 0.25f;
|
|
break;
|
|
case 3:
|
|
m_DropShipWait.z += dist*BOARD_RADIUS;
|
|
m_DropShipWait.x += dist*BOARD_RADIUS;
|
|
m_DropShipBoard.z += dist*BOARD_RADIUS;
|
|
m_DropShipFinal.z += dist * 0.5f;
|
|
m_DropShipFinal.x += dist * 0.25f;
|
|
break;
|
|
case 4:
|
|
m_DropShipWait.z += dist*BOARD_RADIUS*2.0f;
|
|
m_DropShipBoard.z += dist*BOARD_RADIUS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MoverAI::PrepareBoardDropShip (void)
|
|
{
|
|
int speed;
|
|
|
|
m_BoardingDropShip = DROP_FIRST_POINT;
|
|
speed = ConvertKPHtoMPS (1000);
|
|
|
|
orderMoveToLocPoint (m_DropShipWait,speed,true,true);
|
|
if (m_DropShipID == 0)
|
|
{
|
|
m_CanStartBoard = true;
|
|
}
|
|
}
|
|
|
|
void MoverAI::CheckDropBoard (Time delta)
|
|
{
|
|
|
|
if (m_ReadyToStart && m_CanStartBoard)
|
|
{
|
|
NextBoardDropShip ();
|
|
return;
|
|
}
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
Point3D dest (0,0,0);
|
|
|
|
switch (m_BoardingDropShip)
|
|
{
|
|
case DROP_NOT_ACTIVE:
|
|
#if defined(LAB_ONLY)
|
|
PAUSE (("check board drop ship called when not boarding a dropship"));
|
|
#endif
|
|
return;
|
|
break;
|
|
case DROP_FIRST_POINT: // check for at wait point
|
|
dest = m_DropShipWait;
|
|
break;
|
|
case DROP_SECOND_POINT: // check for at point in front of doors
|
|
dest = m_DropShipBoard;
|
|
break;
|
|
case DROP_THIRD_POINT: // check for at center point
|
|
dest = m_DropShipCenter;
|
|
break;
|
|
case DROP_FOURTH_POINT: // check for at final point
|
|
dest = m_DropShipFinal;
|
|
break;
|
|
case DROP_DONE:
|
|
return;
|
|
break;
|
|
}
|
|
Scalar dist,speed;
|
|
Point3D extra;
|
|
|
|
speed = m_Vehicle->currentSpeedMPS;
|
|
speed *= speed;
|
|
extra.Subtract (dest,loc);
|
|
dist = extra.GetLengthSquared ();
|
|
if ((dist<49.0f) || (dist < speed))
|
|
{
|
|
ClearMoveOrder ();
|
|
if (m_BoardingDropShip == DROP_FIRST_POINT)
|
|
m_ReadyToStart = true;
|
|
else
|
|
NextBoardDropShip ();
|
|
}
|
|
if ((m_BoardingDropShip == DROP_THIRD_POINT) && (m_DropShipID != 4))
|
|
{
|
|
if (m_OtherDropShipBoarders[m_DropShipID+1])
|
|
{
|
|
m_OtherDropShipBoarders[m_DropShipID+1]->StartDropShipBoard ();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MoverAI::NextBoardDropShip (void)
|
|
{
|
|
Scalar normalspeed,endspeed;
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
switch (m_BoardingDropShip)
|
|
{
|
|
#if defined(LAB_ONLY)
|
|
case DROP_NOT_ACTIVE:
|
|
PAUSE (("next board drop ship called when not boarding a dropship"));
|
|
break;
|
|
#endif
|
|
case DROP_FIRST_POINT: // at wait point ready to point in front of doors
|
|
m_BoardingDropShip = DROP_SECOND_POINT;
|
|
m_ReadyToStart = false;
|
|
m_CanStartBoard = false;
|
|
normalspeed = ((float) ConvertKPHtoMPS(35)) / ((float) model->maxSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPS(25)) / ((float) model->maxSpeed);
|
|
SetMoveHead (m_DropShipBoard,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
break;
|
|
case DROP_SECOND_POINT: // at point in front of doors, ready to go to center
|
|
m_BoardingDropShip = DROP_THIRD_POINT;
|
|
normalspeed = ((float) ConvertKPHtoMPS(25)) / ((float) model->maxSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPS(25)) / ((float) model->maxSpeed);
|
|
SetMoveHead (m_DropShipCenter,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
break;
|
|
case DROP_THIRD_POINT: // at center ready to go to final
|
|
if (m_DropShipID == 4)
|
|
{
|
|
m_BoardingDropShip = DROP_DONE;
|
|
ClearMoveOrder ();
|
|
}
|
|
else
|
|
{
|
|
m_BoardingDropShip = DROP_FOURTH_POINT;
|
|
normalspeed = ((float) ConvertKPHtoMPS(25)) / ((float) model->maxSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPS(0)) / ((float) model->maxSpeed);
|
|
SetMoveHead (m_DropShipFinal,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
}
|
|
break;
|
|
case DROP_FOURTH_POINT: // at final ready to stop
|
|
m_BoardingDropShip = DROP_DONE;
|
|
ClearMoveOrder ();
|
|
break;
|
|
#if defined(LAB_ONLY)
|
|
case DROP_DONE:
|
|
PAUSE (("next board drop ship called when done boarding a dropship"));
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void MoverAI::FieldBaseDead (void)
|
|
{
|
|
Scalar normalspeed,endspeed;
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
m_Vehicle->ShutDownRequest(false);
|
|
m_EnteringFieldBase = FIELDBASE_DEAD;
|
|
if (m_FieldBaseReverse)
|
|
{
|
|
normalspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxReverseSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxReverseSpeed);
|
|
}
|
|
else
|
|
{
|
|
normalspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxSpeed);
|
|
}
|
|
SetMoveHead (m_FieldBaseExit,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
}
|
|
|
|
void MoverAI::NextFieldBase (bool frommover)
|
|
{
|
|
Scalar normalspeed,endspeed;
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
switch (m_EnteringFieldBase)
|
|
{
|
|
case FIELDBASE_NOT_ACTIVE:
|
|
#ifdef LAB_ONLY
|
|
PAUSE (("check field base called when not entering a field base"));
|
|
#endif
|
|
return;
|
|
break;
|
|
case FIELDBASE_ENTER:
|
|
m_EnteringFieldBase = FIELDBASE_HEAL;
|
|
Shutdown ();
|
|
break;
|
|
case FIELDBASE_EXIT: // at point in front of doors, ready to go to center
|
|
m_EnteringFieldBase = FIELDBASE_NOT_ACTIVE;
|
|
FinishFieldBase ();
|
|
m_ScriptRunning = true;
|
|
break;
|
|
case FIELDBASE_HEAL: // at center ready to go to final
|
|
m_EnteringFieldBase = FIELDBASE_EXIT;
|
|
if (m_FieldBaseReverse)
|
|
{
|
|
normalspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxReverseSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxReverseSpeed);
|
|
}
|
|
else
|
|
{
|
|
normalspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxSpeed);
|
|
}
|
|
SetMoveHead (m_FieldBaseExit,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
break;
|
|
case FIELDBASE_DEAD:
|
|
if (frommover)
|
|
{
|
|
m_EnteringFieldBase = FIELDBASE_NOT_ACTIVE;
|
|
FinishFieldBase ();
|
|
m_ScriptRunning = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MoverAI::LancemateFieldBasePoint (Stuff::Point3D &pt,FieldBase *base)
|
|
{
|
|
Check_Object (base);
|
|
pt = (Point3D) m_FieldBase->GetLocalToWorld ();
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = base->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = base->GetSolidVolume ();
|
|
Verify (col);
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, base->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
|
|
Scalar dist = obb->sphereRadius;
|
|
|
|
UnitVector3D p1,p2;
|
|
Point3D extra,otherloc;
|
|
base->GetLocalToWorld ().GetLocalForwardInWorld (&p1);
|
|
Scalar dot1 = 5.0f;
|
|
otherloc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
extra.Subtract (otherloc,pt);
|
|
if (Small_Enough (extra.GetLengthSquared ())) // get point in reference to us
|
|
dot1 = 0.0f;
|
|
else
|
|
{
|
|
p2 = extra;
|
|
dot1 = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
|
|
Vector3D dir (p1);
|
|
dir *= (dist*3.0f);
|
|
if (dot1 > 0)
|
|
{
|
|
dir.x *= -1.0f;
|
|
dir.z *= -1.0f;
|
|
pt.Add (pt,dir);
|
|
}
|
|
}
|
|
|
|
void MoverAI::CheckFieldBase (Stuff::Time delta)
|
|
{
|
|
Point3D loc (m_Vehicle->GetLocalToWorld ());
|
|
Point3D dest (0,0,0);
|
|
|
|
if (m_FieldBase->IsDestroyed () && m_EnteringFieldBase != FIELDBASE_DEAD)
|
|
FieldBaseDead ();
|
|
|
|
switch (m_EnteringFieldBase)
|
|
{
|
|
case FIELDBASE_NOT_ACTIVE:
|
|
#ifdef LAB_ONLY
|
|
PAUSE (("check field base called when not entering a field base"));
|
|
#endif
|
|
return;
|
|
break;
|
|
case FIELDBASE_ENTER:
|
|
dest = m_FieldBaseEnter;
|
|
break;
|
|
case FIELDBASE_HEAL:
|
|
return;
|
|
break;
|
|
case FIELDBASE_DEAD:
|
|
dest = m_FieldBaseExit;
|
|
FieldBaseDead ();
|
|
break;
|
|
case FIELDBASE_EXIT:
|
|
dest = m_FieldBaseExit;
|
|
break;
|
|
}
|
|
Scalar dist,speed;
|
|
Point3D extra;
|
|
|
|
speed = m_Vehicle->currentSpeedMPS;
|
|
speed *= speed;
|
|
extra.Subtract (dest,loc);
|
|
dist = extra.GetLengthSquared ();
|
|
if (m_ShouldEndFieldBase)
|
|
{
|
|
ClearMoveOrder ();
|
|
NextFieldBase (true);
|
|
return;
|
|
}
|
|
if ((dist<9.0f) || (dist < speed))
|
|
{
|
|
if ((m_EnteringFieldBase == FIELDBASE_EXIT) || (m_EnteringFieldBase == FIELDBASE_DEAD))
|
|
{
|
|
m_ShouldEndFieldBase = true; // exit should work on the next frame.
|
|
}
|
|
else
|
|
{
|
|
ClearMoveOrder ();
|
|
NextFieldBase (true);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MoverAI::CreateFieldBasePoints (FieldBase *base)
|
|
{
|
|
if (m_EnteringFieldBase != FIELDBASE_NOT_ACTIVE)
|
|
return true;
|
|
|
|
if ((base->m_CurrentMechUsing) && (base->m_CurrentMechUsing != this))
|
|
return false;
|
|
|
|
m_FieldBaseReverse = false;
|
|
if (m_Vehicle->currentSpeedMPS < 0)
|
|
m_FieldBaseReverse = true;
|
|
|
|
m_ShouldEndFieldBase = false;
|
|
Check_Object (base);
|
|
m_FieldBase = base;
|
|
m_FieldBaseEnter = (Point3D) m_FieldBase->GetLocalToWorld ();
|
|
OBB *obb;
|
|
CollisionVolume *col;
|
|
col = m_FieldBase->GetHierarchicalVolume ();
|
|
if (!col)
|
|
col = m_FieldBase->GetSolidVolume ();
|
|
Verify (col);
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(col->m_localSpaceBounds, base->GetLocalToWorld());
|
|
obb = &(world_bounds);
|
|
|
|
Scalar dist = obb->sphereRadius;
|
|
m_FieldBaseExit = m_FieldBaseEnter;
|
|
|
|
UnitVector3D p1,p2;
|
|
Point3D extra,otherloc;
|
|
m_FieldBase->GetLocalToWorld ().GetLocalForwardInWorld (&p1);
|
|
Scalar dot1 = 5.0f;
|
|
otherloc = (Point3D) m_Vehicle->GetLocalToWorld ();
|
|
extra.Subtract (otherloc,m_FieldBaseEnter);
|
|
if (Small_Enough (extra.GetLengthSquared ())) // get point in reference to us
|
|
dot1 = 0.0f;
|
|
else
|
|
{
|
|
p2 = extra;
|
|
dot1 = (p1.x*p2.x) + (p1.z*p2.z);
|
|
}
|
|
|
|
Vector3D dir (p1);
|
|
Scalar fred;
|
|
fred = m_Vehicle->currentSpeedMPS * 3.6f;
|
|
if (fred < 0)
|
|
fred = -fred;
|
|
|
|
if (fred > 35.0f)
|
|
{
|
|
dir *= (dist*2.5f);
|
|
}
|
|
else
|
|
dir *= (dist*1.5f);
|
|
if (dot1 <= -0.965f) // point is behind us, and cos(15) degrees
|
|
{
|
|
m_FieldBaseExit.Add (m_FieldBaseEnter,dir);
|
|
}
|
|
else if (dot1 > 0.965f) // cos (15) degrees
|
|
{
|
|
dir.x *= -1.0f;
|
|
dir.z *= -1.0f;
|
|
m_FieldBaseExit.Add (m_FieldBaseEnter,dir);
|
|
}
|
|
else
|
|
return false;
|
|
|
|
base->m_CurrentMechUsing = this;
|
|
return true;
|
|
}
|
|
void MoverAI::PrepareEnterFieldBase (void)
|
|
{
|
|
m_ScriptRunning = false;
|
|
Scalar normalspeed,endspeed;
|
|
const Vehicle__GameModel *model = static_cast<const Vehicle__GameModel *> (m_Vehicle->GetGameModel ()) ;
|
|
Check_Object (model);
|
|
|
|
m_FieldBaseReverse = false;
|
|
if (m_Vehicle->currentSpeedMPS < 0)
|
|
m_FieldBaseReverse = true;
|
|
|
|
Scalar fred;
|
|
fred = m_Vehicle->currentSpeedMPS * 3.6f;
|
|
if (fred < 0)
|
|
fred = -fred;
|
|
if (fred > 35.0f)
|
|
{
|
|
m_EnteringFieldBase = FIELDBASE_EXIT;
|
|
if (m_FieldBaseReverse)
|
|
{
|
|
normalspeed = ((float) m_Vehicle->currentSpeedMPS) / ((float) model->maxReverseSpeed);
|
|
endspeed = ((float) m_Vehicle->currentSpeedMPS) / ((float) model->maxReverseSpeed);
|
|
normalspeed = -normalspeed;
|
|
endspeed = -endspeed;
|
|
}
|
|
else
|
|
{
|
|
normalspeed = ((float) m_Vehicle->currentSpeedMPS) / ((float) model->maxSpeed);
|
|
endspeed = ((float) m_Vehicle->currentSpeedMPS) / ((float) model->maxSpeed);
|
|
}
|
|
SetMoveHead (m_FieldBaseExit,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
}
|
|
else
|
|
{
|
|
m_EnteringFieldBase = FIELDBASE_ENTER;
|
|
if (m_FieldBaseReverse)
|
|
{
|
|
normalspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxReverseSpeed);
|
|
endspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) model->maxReverseSpeed);
|
|
}
|
|
else
|
|
{
|
|
normalspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) m_Vehicle->GetMaxSpeed ());
|
|
endspeed = ((float) ConvertKPHtoMPSFloat(25)) / ((float) m_Vehicle->GetMaxSpeed ());
|
|
// normalspeed = ((float) ConvertKPHtoMPS(25)) / ((float) model->maxSpeed);
|
|
// endspeed = ((float) ConvertKPHtoMPS(25)) / ((float) model->maxSpeed);
|
|
}
|
|
|
|
SetMoveHead (m_FieldBaseEnter,normalspeed,Point3D (-1,-1,-1),endspeed);
|
|
}
|
|
}
|
|
|
|
|
|
void MoverAI::FinishFieldBase (void)
|
|
{
|
|
if (m_FieldBase->m_CurrentMechUsing == this)
|
|
{
|
|
m_FieldBase->m_CurrentMechUsing = NULL;
|
|
}
|
|
Startup();
|
|
m_LastTimeFinishedFieldBase = (Stuff::Scalar)gos_GetElapsedTime();
|
|
}
|
|
|
|
bool MoverAI::ExitedFieldBaseRecently() const
|
|
{
|
|
if (m_LastTimeFinishedFieldBase == 0)
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
Stuff::Scalar t = (Stuff::Scalar)gos_GetElapsedTime();
|
|
|
|
if ((t > m_LastTimeFinishedFieldBase) &&
|
|
(t < m_LastTimeFinishedFieldBase + 5.0f))
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|