Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

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(&current_motion);
else
m_Vehicle->GetLocalToWorld().GetLocalForwardInWorld(&current_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);
}