//===========================================================================// // 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 #include "mwobject.hpp" #include "building.hpp" #include #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 #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::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 (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 (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 *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; iGetLength(); ++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; iGetLength(); ++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; iGetLength(); ++i) { CollisionData *data = &(*collisions)[i]; Check_Object(data); Check_Object(data->m_otherEntity); Verify(this != data->m_otherEntity); Verify(GetInterestLevel() != DormantInterestLevel); Check_Object(m_Vehicle); // if ((data->m_otherEntity->IsACollider()) || (data->m_otherEntity->IsACollide ())) { Vector3D vector_to_target; Point3D local_to_world(m_Vehicle->GetLocalToWorld()); Point3D target_local_to_world(data->m_otherEntity->GetLocalToWorld()); if ((data->m_otherEntity->GetWalkThruType () == AnythingCanWalkThruType) && (m_Vehicle->GetClassID () == MechClassID)) return true; vector_to_target.Subtract(target_local_to_world, local_to_world); UnitVector3D current_motion; if (m_OrderSpeed < 0) m_Vehicle->GetLocalToWorld().GetLocalBackwardInWorld(¤t_motion); else m_Vehicle->GetLocalToWorld().GetLocalForwardInWorld(¤t_motion); Scalar dot_product; dot_product = current_motion * vector_to_target; if (dot_product <= 0.0f) // collision behind us to ignore, trying to move away continue; if (EqualRamTarget (data->m_otherEntity)) { shoulddamage = true; return true; } HandleObstacle (data->m_otherEntity); shoulddamage = false; } return true; } return false; // unknown type so ignore collision } void MoverAI::PathDone (Stuff::Time till,bool failed) { Check_Object (this); if (m_CurMove) { m_CurMove->PathDone (this,till,failed); } if (!failed) { if ((m_CurMove) && (m_CurMove->Done ())) NotifyReachedDestination (); else if (!m_CurMove) NotifyReachedDestination (); m_FailCount = 0; } } void MoverAI::SetMoveHead (const Stuff::Point3D& head,Stuff::Scalar speedreq,const Stuff::Point3D& outvec,Stuff::Scalar endspeed) { Check_Object (this); m_NewMoveHead = head; m_NewOutVec = outvec; if (m_NewMoveHead == Point3D (-1,-1,-1)) { speedreq = 0; } m_NewSpeedRequest = speedreq; m_NewEndSpeedRequest = endspeed < speedreq ? endspeed : speedreq; } void MoverAI::ClearPathLock (bool quitting,bool fromram) { Check_Object (this); MOVER_LOGIC("ClearPathLock"); #if !defined(NO_TIMERS) my_AutoTimer fred ((void *) &tDynamicObstacleTime); #endif AutoHeap local_heap (g_MoverAIHeap); Verify (m_LockedRects.size () == 0); stlport::vector::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::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::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::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::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::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 (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;ivehicle; 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 (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 (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 (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 (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 (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 (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 *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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 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 (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 (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 (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 (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); }